commit
8b3c09a103
61 changed files with 3052 additions and 1122 deletions
|
@ -95,9 +95,10 @@ pub use str::{StrSlice};
|
|||
pub use container::{Container, Mutable};
|
||||
pub use vec::{CopyableVector, ImmutableVector};
|
||||
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
|
||||
pub use vec::{OwnedVector, OwnedCopyableVector};
|
||||
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
|
||||
pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter};
|
||||
pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times};
|
||||
pub use iter::{ExtendedMutableIter};
|
||||
|
||||
pub use num::{Num, NumCast};
|
||||
pub use ptr::Ptr;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
use container::{Container, Mutable, Map, Set};
|
||||
use cmp::{Eq, Equiv};
|
||||
use hash::Hash;
|
||||
use to_bytes::IterBytes;
|
||||
use iter::BaseIter;
|
||||
use hash::Hash;
|
||||
use iter;
|
||||
|
@ -72,7 +71,7 @@ fn linear_map_with_capacity_and_keys<K:Eq + Hash,V>(
|
|||
}
|
||||
}
|
||||
|
||||
priv impl<K:Hash + IterBytes + Eq,V> HashMap<K, V> {
|
||||
priv impl<K:Hash + Eq,V> HashMap<K, V> {
|
||||
#[inline(always)]
|
||||
fn to_bucket(&self, h: uint) -> uint {
|
||||
// A good hash function with entropy spread over all of the
|
||||
|
@ -111,9 +110,8 @@ priv impl<K:Hash + IterBytes + Eq,V> HashMap<K, V> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn bucket_for_key_equiv<Q:Hash + IterBytes + Equiv<K>>(&self,
|
||||
k: &Q)
|
||||
-> SearchResult {
|
||||
fn bucket_for_key_equiv<Q:Hash + Equiv<K>>(&self, k: &Q)
|
||||
-> SearchResult {
|
||||
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
||||
self.bucket_for_key_with_hash_equiv(hash, k)
|
||||
}
|
||||
|
@ -303,7 +301,7 @@ priv impl<K:Hash + IterBytes + Eq,V> HashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<K:Hash + IterBytes + Eq,V> Container for HashMap<K, V> {
|
||||
impl<K:Hash + Eq,V> Container for HashMap<K, V> {
|
||||
/// Return the number of elements in the map
|
||||
fn len(&const self) -> uint { self.size }
|
||||
|
||||
|
@ -311,7 +309,7 @@ impl<K:Hash + IterBytes + Eq,V> Container for HashMap<K, V> {
|
|||
fn is_empty(&const self) -> bool { self.len() == 0 }
|
||||
}
|
||||
|
||||
impl<K:Hash + IterBytes + Eq,V> Mutable for HashMap<K, V> {
|
||||
impl<K:Hash + Eq,V> Mutable for HashMap<K, V> {
|
||||
/// Clear the map, removing all key-value pairs.
|
||||
fn clear(&mut self) {
|
||||
for uint::range(0, self.buckets.len()) |idx| {
|
||||
|
@ -321,7 +319,7 @@ impl<K:Hash + IterBytes + Eq,V> Mutable for HashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<K:Hash + IterBytes + Eq,V> Map<K, V> for HashMap<K, V> {
|
||||
impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> {
|
||||
/// Return true if the map contains a value for the specified key
|
||||
fn contains_key(&self, k: &K) -> bool {
|
||||
match self.bucket_for_key(k) {
|
||||
|
@ -458,7 +456,7 @@ impl<K:Hash + IterBytes + Eq,V> Map<K, V> for HashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> {
|
||||
pub impl<K: Hash + Eq, V> HashMap<K, V> {
|
||||
/// Create an empty HashMap
|
||||
fn new() -> HashMap<K, V> {
|
||||
HashMap::with_capacity(INITIAL_CAPACITY)
|
||||
|
@ -669,8 +667,7 @@ pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> {
|
|||
|
||||
/// Return true if the map contains a value for the specified key,
|
||||
/// using equivalence
|
||||
fn contains_key_equiv<Q:Hash + IterBytes + Equiv<K>>(&self, key: &Q)
|
||||
-> bool {
|
||||
fn contains_key_equiv<Q:Hash + Equiv<K>>(&self, key: &Q) -> bool {
|
||||
match self.bucket_for_key_equiv(key) {
|
||||
FoundEntry(_) => {true}
|
||||
TableFull | FoundHole(_) => {false}
|
||||
|
@ -680,8 +677,7 @@ pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> {
|
|||
/// Return the value corresponding to the key in the map, using
|
||||
/// equivalence
|
||||
#[cfg(stage0)]
|
||||
fn find_equiv<Q:Hash + IterBytes + Equiv<K>>(&self, k: &Q)
|
||||
-> Option<&'self V> {
|
||||
fn find_equiv<Q:Hash + Equiv<K>>(&self, k: &Q) -> Option<&'self V> {
|
||||
match self.bucket_for_key_equiv(k) {
|
||||
FoundEntry(idx) => Some(self.value_for_bucket(idx)),
|
||||
TableFull | FoundHole(_) => None,
|
||||
|
@ -693,9 +689,7 @@ pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> {
|
|||
#[cfg(stage1)]
|
||||
#[cfg(stage2)]
|
||||
#[cfg(stage3)]
|
||||
fn find_equiv<'a, Q:Hash + IterBytes + Equiv<K>>(
|
||||
&'a self, k: &Q) -> Option<&'a V>
|
||||
{
|
||||
fn find_equiv<'a, Q:Hash + Equiv<K>>(&'a self, k: &Q) -> Option<&'a V> {
|
||||
match self.bucket_for_key_equiv(k) {
|
||||
FoundEntry(idx) => Some(self.value_for_bucket(idx)),
|
||||
TableFull | FoundHole(_) => None,
|
||||
|
@ -703,7 +697,7 @@ pub impl<K: Hash + IterBytes + Eq, V> HashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<K:Hash + IterBytes + Eq,V:Eq> Eq for HashMap<K, V> {
|
||||
impl<K:Hash + Eq,V:Eq> Eq for HashMap<K, V> {
|
||||
fn eq(&self, other: &HashMap<K, V>) -> bool {
|
||||
if self.len() != other.len() { return false; }
|
||||
|
||||
|
@ -724,18 +718,18 @@ pub struct HashSet<T> {
|
|||
priv map: HashMap<T, ()>
|
||||
}
|
||||
|
||||
impl<T:Hash + IterBytes + Eq> BaseIter<T> for HashSet<T> {
|
||||
impl<T:Hash + Eq> BaseIter<T> for HashSet<T> {
|
||||
/// Visit all values in order
|
||||
fn each(&self, f: &fn(&T) -> bool) { self.map.each_key(f) }
|
||||
fn size_hint(&self) -> Option<uint> { Some(self.len()) }
|
||||
}
|
||||
|
||||
impl<T:Hash + IterBytes + Eq> Eq for HashSet<T> {
|
||||
impl<T:Hash + Eq> Eq for HashSet<T> {
|
||||
fn eq(&self, other: &HashSet<T>) -> bool { self.map == other.map }
|
||||
fn ne(&self, other: &HashSet<T>) -> bool { self.map != other.map }
|
||||
}
|
||||
|
||||
impl<T:Hash + IterBytes + Eq> Container for HashSet<T> {
|
||||
impl<T:Hash + Eq> Container for HashSet<T> {
|
||||
/// Return the number of elements in the set
|
||||
fn len(&const self) -> uint { self.map.len() }
|
||||
|
||||
|
@ -743,12 +737,12 @@ impl<T:Hash + IterBytes + Eq> Container for HashSet<T> {
|
|||
fn is_empty(&const self) -> bool { self.map.is_empty() }
|
||||
}
|
||||
|
||||
impl<T:Hash + IterBytes + Eq> Mutable for HashSet<T> {
|
||||
impl<T:Hash + Eq> Mutable for HashSet<T> {
|
||||
/// Clear the set, removing all values.
|
||||
fn clear(&mut self) { self.map.clear() }
|
||||
}
|
||||
|
||||
impl<T:Hash + IterBytes + Eq> Set<T> for HashSet<T> {
|
||||
impl<T:Hash + Eq> Set<T> for HashSet<T> {
|
||||
/// Return true if the set contains a value
|
||||
fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
|
||||
|
||||
|
@ -816,7 +810,7 @@ impl<T:Hash + IterBytes + Eq> Set<T> for HashSet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub impl <T:Hash + IterBytes + Eq> HashSet<T> {
|
||||
pub impl <T:Hash + Eq> HashSet<T> {
|
||||
/// Create an empty HashSet
|
||||
fn new() -> HashSet<T> {
|
||||
HashSet::with_capacity(INITIAL_CAPACITY)
|
||||
|
|
|
@ -45,6 +45,10 @@ pub trait ExtendedIter<A> {
|
|||
fn flat_map_to_vec<B,IB: BaseIter<B>>(&self, op: &fn(&A) -> IB) -> ~[B];
|
||||
}
|
||||
|
||||
pub trait ExtendedMutableIter<A> {
|
||||
fn eachi_mut(&mut self, blk: &fn(uint, &mut A) -> bool);
|
||||
}
|
||||
|
||||
pub trait EqIter<A:Eq> {
|
||||
fn contains(&self, x: &A) -> bool;
|
||||
fn count(&self, x: &A) -> uint;
|
||||
|
|
|
@ -1097,9 +1097,12 @@ pub mod funcs {
|
|||
unsafe fn setbuf(stream: *FILE, buf: *c_char);
|
||||
// Omitted: printf and scanf variants.
|
||||
unsafe fn fgetc(stream: *FILE) -> c_int;
|
||||
#[fast_ffi]
|
||||
unsafe fn fgets(buf: *mut c_char, n: c_int,
|
||||
stream: *FILE) -> *c_char;
|
||||
#[fast_ffi]
|
||||
unsafe fn fputc(c: c_int, stream: *FILE) -> c_int;
|
||||
#[fast_ffi]
|
||||
unsafe fn fputs(s: *c_char, stream: *FILE) -> *c_char;
|
||||
// Omitted: getc, getchar (might be macros).
|
||||
|
||||
|
@ -1109,8 +1112,10 @@ pub mod funcs {
|
|||
// Omitted: putc, putchar (might be macros).
|
||||
unsafe fn puts(s: *c_char) -> c_int;
|
||||
unsafe fn ungetc(c: c_int, stream: *FILE) -> c_int;
|
||||
#[fast_ffi]
|
||||
unsafe fn fread(ptr: *mut c_void, size: size_t,
|
||||
nobj: size_t, stream: *FILE) -> size_t;
|
||||
#[fast_ffi]
|
||||
unsafe fn fwrite(ptr: *c_void, size: size_t,
|
||||
nobj: size_t, stream: *FILE) -> size_t;
|
||||
unsafe fn fseek(stream: *FILE, offset: c_long,
|
||||
|
@ -1144,9 +1149,13 @@ pub mod funcs {
|
|||
-> c_long;
|
||||
unsafe fn strtoul(s: *c_char, endp: **c_char, base: c_int)
|
||||
-> c_ulong;
|
||||
#[fast_ffi]
|
||||
unsafe fn calloc(nobj: size_t, size: size_t) -> *c_void;
|
||||
#[fast_ffi]
|
||||
unsafe fn malloc(size: size_t) -> *c_void;
|
||||
#[fast_ffi]
|
||||
unsafe fn realloc(p: *c_void, size: size_t) -> *c_void;
|
||||
#[fast_ffi]
|
||||
unsafe fn free(p: *c_void);
|
||||
unsafe fn abort() -> !;
|
||||
unsafe fn exit(status: c_int) -> !;
|
||||
|
@ -1257,6 +1266,7 @@ pub mod funcs {
|
|||
unsafe fn pclose(stream: *FILE) -> c_int;
|
||||
|
||||
#[link_name = "_fdopen"]
|
||||
#[fast_ffi]
|
||||
unsafe fn fdopen(fd: c_int, mode: *c_char) -> *FILE;
|
||||
|
||||
#[link_name = "_fileno"]
|
||||
|
@ -1340,6 +1350,7 @@ pub mod funcs {
|
|||
textmode: c_int) -> c_int;
|
||||
|
||||
#[link_name = "_read"]
|
||||
#[fast_ffi]
|
||||
unsafe fn read(fd: c_int, buf: *mut c_void, count: c_uint)
|
||||
-> c_int;
|
||||
|
||||
|
@ -1350,6 +1361,7 @@ pub mod funcs {
|
|||
unsafe fn unlink(c: *c_char) -> c_int;
|
||||
|
||||
#[link_name = "_write"]
|
||||
#[fast_ffi]
|
||||
unsafe fn write(fd: c_int, buf: *c_void, count: c_uint)
|
||||
-> c_int;
|
||||
}
|
||||
|
@ -1502,6 +1514,7 @@ pub mod funcs {
|
|||
unsafe fn pathconf(path: *c_char, name: c_int) -> c_long;
|
||||
unsafe fn pause() -> c_int;
|
||||
unsafe fn pipe(fds: *mut c_int) -> c_int;
|
||||
#[fast_ffi]
|
||||
unsafe fn read(fd: c_int, buf: *mut c_void,
|
||||
count: size_t) -> ssize_t;
|
||||
unsafe fn rmdir(path: *c_char) -> c_int;
|
||||
|
@ -1514,6 +1527,7 @@ pub mod funcs {
|
|||
unsafe fn tcgetpgrp(fd: c_int) -> pid_t;
|
||||
unsafe fn ttyname(fd: c_int) -> *c_char;
|
||||
unsafe fn unlink(c: *c_char) -> c_int;
|
||||
#[fast_ffi]
|
||||
unsafe fn write(fd: c_int, buf: *c_void, count: size_t)
|
||||
-> ssize_t;
|
||||
}
|
||||
|
|
|
@ -503,4 +503,4 @@ mod tests {
|
|||
fn test_range_step_zero_step() {
|
||||
for range_step(0,10,0) |_i| {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -474,4 +474,4 @@ mod tests {
|
|||
fn test_range_step_zero_step_down() {
|
||||
for range_step(0,-10,0) |_i| {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ pub use container::{Container, Mutable, Map, Set};
|
|||
pub use hash::Hash;
|
||||
pub use iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
|
||||
pub use iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter};
|
||||
pub use iter::Times;
|
||||
pub use iter::{Times, ExtendedMutableIter};
|
||||
pub use num::{Num, NumCast};
|
||||
pub use path::GenericPath;
|
||||
pub use path::Path;
|
||||
|
@ -46,7 +46,7 @@ pub use to_str::ToStr;
|
|||
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
|
||||
pub use vec::{CopyableVector, ImmutableVector};
|
||||
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
|
||||
pub use vec::{OwnedVector, OwnedCopyableVector};
|
||||
pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector};
|
||||
pub use io::{Reader, ReaderUtil, Writer, WriterUtil};
|
||||
|
||||
/* Reexported runtime types */
|
||||
|
|
|
@ -67,6 +67,15 @@ pub fn from_bytes_with_null<'a>(vv: &'a [u8]) -> &'a str {
|
|||
return unsafe { raw::from_bytes_with_null(vv) };
|
||||
}
|
||||
|
||||
pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str {
|
||||
unsafe {
|
||||
assert!(is_utf8(vector));
|
||||
let (ptr, len): (*u8, uint) = ::cast::transmute(vector);
|
||||
let string: &'a str = ::cast::transmute((ptr, len + 1));
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy a slice into a new unique str
|
||||
pub fn from_slice(s: &str) -> ~str {
|
||||
unsafe { raw::slice_bytes_owned(s, 0, len(s)) }
|
||||
|
@ -421,6 +430,15 @@ pub fn byte_slice<T>(s: &str, f: &fn(v: &[u8]) -> T) -> T {
|
|||
}
|
||||
}
|
||||
|
||||
/// Work with the string as a byte slice, not including trailing null, without
|
||||
/// a callback.
|
||||
#[inline(always)]
|
||||
pub fn byte_slice_no_callback<'a>(s: &'a str) -> &'a [u8] {
|
||||
unsafe {
|
||||
cast::transmute(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a string to a unique vector of characters
|
||||
pub fn to_chars(s: &str) -> ~[char] {
|
||||
let mut buf = ~[];
|
||||
|
|
|
@ -35,6 +35,14 @@ pub mod rustrt {
|
|||
|
||||
#[rust_stack]
|
||||
unsafe fn rust_upcall_free(ptr: *c_char);
|
||||
|
||||
#[fast_ffi]
|
||||
unsafe fn rust_upcall_malloc_noswitch(td: *c_char,
|
||||
size: uintptr_t)
|
||||
-> *c_char;
|
||||
|
||||
#[fast_ffi]
|
||||
unsafe fn rust_upcall_free_noswitch(ptr: *c_char);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +89,7 @@ pub unsafe fn exchange_free(ptr: *c_char) {
|
|||
#[lang="malloc"]
|
||||
#[inline(always)]
|
||||
pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
|
||||
return rustrt::rust_upcall_malloc(td, size);
|
||||
return rustrt::rust_upcall_malloc_noswitch(td, size);
|
||||
}
|
||||
|
||||
// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
|
||||
|
@ -90,7 +98,7 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
|
|||
#[lang="free"]
|
||||
#[inline(always)]
|
||||
pub unsafe fn local_free(ptr: *c_char) {
|
||||
rustrt::rust_upcall_free(ptr);
|
||||
rustrt::rust_upcall_free_noswitch(ptr);
|
||||
}
|
||||
|
||||
#[lang="borrow_as_imm"]
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
|
||||
#[warn(non_camel_case_types)];
|
||||
|
||||
use container::{Container, Mutable};
|
||||
use cast::transmute;
|
||||
use cast;
|
||||
use container::{Container, Mutable};
|
||||
use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
|
||||
use clone::Clone;
|
||||
use iter::BaseIter;
|
||||
|
@ -43,9 +44,11 @@ pub mod rustrt {
|
|||
pub extern {
|
||||
// These names are terrible. reserve_shared applies
|
||||
// to ~[] and reserve_shared_actual applies to @[].
|
||||
#[fast_ffi]
|
||||
unsafe fn vec_reserve_shared(++t: *sys::TypeDesc,
|
||||
++v: **raw::VecRepr,
|
||||
++n: libc::size_t);
|
||||
#[fast_ffi]
|
||||
unsafe fn vec_reserve_shared_actual(++t: *sys::TypeDesc,
|
||||
++v: **raw::VecRepr,
|
||||
++n: libc::size_t);
|
||||
|
@ -73,6 +76,7 @@ pub fn same_length<T, U>(xs: &const [T], ys: &const [U]) -> bool {
|
|||
* * v - A vector
|
||||
* * n - The number of elements to reserve space for
|
||||
*/
|
||||
#[inline]
|
||||
pub fn reserve<T>(v: &mut ~[T], n: uint) {
|
||||
// Only make the (slow) call into the runtime if we have to
|
||||
use managed;
|
||||
|
@ -1386,13 +1390,19 @@ pub fn each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) {
|
|||
/// to mutate the contents as you iterate.
|
||||
#[inline(always)]
|
||||
pub fn each_mut<'r,T>(v: &'r mut [T], f: &fn(elem: &'r mut T) -> bool) {
|
||||
let mut i = 0;
|
||||
let n = v.len();
|
||||
while i < n {
|
||||
if !f(&mut v[i]) {
|
||||
return;
|
||||
do vec::as_mut_buf(v) |p, n| {
|
||||
let mut n = n;
|
||||
let mut p = p;
|
||||
while n > 0 {
|
||||
unsafe {
|
||||
let q: &'r mut T = cast::transmute_mut_region(&mut *p);
|
||||
if !f(q) {
|
||||
break;
|
||||
}
|
||||
p = p.offset(1);
|
||||
}
|
||||
n -= 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1424,6 +1434,22 @@ pub fn eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over a mutable vector's elements and indices
|
||||
*
|
||||
* Return true to continue, false to break.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn eachi_mut<'r,T>(v: &'r mut [T], f: &fn(uint, v: &'r mut T) -> bool) {
|
||||
let mut i = 0;
|
||||
for each_mut(v) |p| {
|
||||
if !f(i, p) {
|
||||
return;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over a vector's elements in reverse
|
||||
*
|
||||
|
@ -1806,6 +1832,7 @@ pub trait ImmutableVector<T> {
|
|||
fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool;
|
||||
fn flat_map<U>(&self, f: &fn(t: &T) -> ~[U]) -> ~[U];
|
||||
fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U];
|
||||
unsafe fn unsafe_ref(&self, index: uint) -> *T;
|
||||
}
|
||||
|
||||
/// Extension methods for vectors
|
||||
|
@ -1916,6 +1943,14 @@ impl<'self,T> ImmutableVector<T> for &'self [T] {
|
|||
fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U] {
|
||||
filter_mapped(*self, f)
|
||||
}
|
||||
|
||||
/// Returns a pointer to the element at the given index, without doing
|
||||
/// bounds checking.
|
||||
#[inline(always)]
|
||||
unsafe fn unsafe_ref(&self, index: uint) -> *T {
|
||||
let (ptr, _): (*T, uint) = transmute(*self);
|
||||
ptr.offset(index)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage1)]
|
||||
|
@ -1941,6 +1976,7 @@ pub trait ImmutableVector<'self, T> {
|
|||
fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool;
|
||||
fn flat_map<U>(&self, f: &fn(t: &T) -> ~[U]) -> ~[U];
|
||||
fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U];
|
||||
unsafe fn unsafe_ref(&self, index: uint) -> *T;
|
||||
}
|
||||
|
||||
/// Extension methods for vectors
|
||||
|
@ -2062,6 +2098,14 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
|
|||
fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U] {
|
||||
filter_mapped(*self, f)
|
||||
}
|
||||
|
||||
/// Returns a pointer to the element at the given index, without doing
|
||||
/// bounds checking.
|
||||
#[inline(always)]
|
||||
unsafe fn unsafe_ref(&self, index: uint) -> *T {
|
||||
let (ptr, _): (*T, uint) = transmute(*self);
|
||||
ptr.offset(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ImmutableEqVector<T:Eq> {
|
||||
|
@ -2113,6 +2157,7 @@ pub trait ImmutableCopyableVector<T> {
|
|||
fn filtered(&self, f: &fn(&T) -> bool) -> ~[T];
|
||||
fn rfind(&self, f: &fn(t: &T) -> bool) -> Option<T>;
|
||||
fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]);
|
||||
unsafe fn unsafe_get(&self, elem: uint) -> T;
|
||||
}
|
||||
|
||||
/// Extension methods for vectors
|
||||
|
@ -2149,6 +2194,12 @@ impl<'self,T:Copy> ImmutableCopyableVector<T> for &'self [T] {
|
|||
fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]) {
|
||||
partitioned(*self, f)
|
||||
}
|
||||
|
||||
/// Returns the element at the given index, without doing bounds checking.
|
||||
#[inline(always)]
|
||||
unsafe fn unsafe_get(&self, index: uint) -> T {
|
||||
*self.unsafe_ref(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OwnedVector<T> {
|
||||
|
@ -2289,6 +2340,25 @@ impl<T:Eq> OwnedEqVector<T> for ~[T] {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait MutableVector<T> {
|
||||
unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T;
|
||||
unsafe fn unsafe_set(&self, index: uint, val: T);
|
||||
}
|
||||
|
||||
impl<'self,T> MutableVector<T> for &'self mut [T] {
|
||||
#[inline(always)]
|
||||
unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T {
|
||||
let pair_ptr: &(*mut T, uint) = transmute(self);
|
||||
let (ptr, _) = *pair_ptr;
|
||||
ptr.offset(index)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn unsafe_set(&self, index: uint, val: T) {
|
||||
*self.unsafe_mut_ref(index) = val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a vector from an unsafe pointer to a buffer
|
||||
*
|
||||
|
@ -2652,6 +2722,13 @@ impl<'self,A> iter::ExtendedIter<A> for &'self [A] {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'self,A> iter::ExtendedMutableIter<A> for &'self mut [A] {
|
||||
#[inline(always)]
|
||||
pub fn eachi_mut(&mut self, blk: &fn(uint, v: &mut A) -> bool) {
|
||||
eachi_mut(*self, blk)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(#4148): This should be redundant
|
||||
impl<A> iter::ExtendedIter<A> for ~[A] {
|
||||
pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) {
|
||||
|
|
|
@ -188,8 +188,10 @@ pub mod write {
|
|||
return false;
|
||||
}
|
||||
|
||||
pub fn run_passes(sess: Session, llmod: ModuleRef,
|
||||
output_type: output_type, output: &Path) {
|
||||
pub fn run_passes(sess: Session,
|
||||
llmod: ModuleRef,
|
||||
output_type: output_type,
|
||||
output: &Path) {
|
||||
unsafe {
|
||||
let opts = sess.opts;
|
||||
if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
|
||||
|
|
|
@ -172,10 +172,13 @@ pub enum compile_upto {
|
|||
|
||||
// For continuing compilation after a parsed crate has been
|
||||
// modified
|
||||
pub fn compile_rest(sess: Session, cfg: ast::crate_cfg,
|
||||
upto: compile_upto, outputs: Option<@OutputFilenames>,
|
||||
#[fixed_stack_segment]
|
||||
pub fn compile_rest(sess: Session,
|
||||
cfg: ast::crate_cfg,
|
||||
upto: compile_upto,
|
||||
outputs: Option<@OutputFilenames>,
|
||||
curr: Option<@ast::crate>)
|
||||
-> (@ast::crate, Option<ty::ctxt>) {
|
||||
-> (@ast::crate, Option<ty::ctxt>) {
|
||||
let time_passes = sess.time_passes();
|
||||
let mut crate = curr.get();
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,7 +37,7 @@ use std::serialize::Decodable;
|
|||
use syntax::ast_map;
|
||||
use syntax::attr;
|
||||
use syntax::diagnostic::span_handler;
|
||||
use syntax::parse::token::{ident_interner, special_idents};
|
||||
use syntax::parse::token::{StringRef, ident_interner, special_idents};
|
||||
use syntax::print::pprust;
|
||||
use syntax::{ast, ast_util};
|
||||
use syntax::codemap;
|
||||
|
@ -249,12 +249,7 @@ fn doc_transformed_self_ty(doc: ebml::Doc,
|
|||
|
||||
pub fn item_type(item_id: ast::def_id, item: ebml::Doc,
|
||||
tcx: ty::ctxt, cdata: cmd) -> ty::t {
|
||||
let t = doc_type(item, tcx, cdata);
|
||||
if family_names_type(item_family(item)) {
|
||||
ty::mk_with_id(tcx, t, item_id)
|
||||
} else {
|
||||
t
|
||||
}
|
||||
doc_type(item, tcx, cdata)
|
||||
}
|
||||
|
||||
fn doc_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::TraitRef {
|
||||
|
@ -327,7 +322,13 @@ fn item_path(intr: @ident_interner, item_doc: ebml::Doc) -> ast_map::path {
|
|||
|
||||
fn item_name(intr: @ident_interner, item: ebml::Doc) -> ast::ident {
|
||||
let name = reader::get_doc(item, tag_paths_data_name);
|
||||
intr.intern(@str::from_bytes(reader::doc_data(name)))
|
||||
do reader::with_doc_data(name) |data| {
|
||||
let string = str::from_bytes_slice(data);
|
||||
match intr.find_equiv(&StringRef(string)) {
|
||||
None => intr.intern(@(string.to_owned())),
|
||||
Some(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num)
|
||||
|
|
|
@ -381,9 +381,9 @@ fn parse_ty(st: @mut PState, conv: conv_did) -> ty::t {
|
|||
}
|
||||
}
|
||||
'"' => {
|
||||
let def = parse_def(st, TypeWithId, conv);
|
||||
let _ = parse_def(st, TypeWithId, conv);
|
||||
let inner = parse_ty(st, conv);
|
||||
ty::mk_with_id(st.tcx, inner, def)
|
||||
inner
|
||||
}
|
||||
'B' => ty::mk_opaque_box(st.tcx),
|
||||
'a' => {
|
||||
|
|
|
@ -78,19 +78,6 @@ pub fn enc_ty(w: @io::Writer, cx: @ctxt, t: ty::t) {
|
|||
Some(a) => { w.write_str(*a.s); return; }
|
||||
None => {
|
||||
let pos = w.tell();
|
||||
match ty::type_def_id(t) {
|
||||
Some(def_id) => {
|
||||
// Do not emit node ids that map to unexported names. Those
|
||||
// are not helpful.
|
||||
if def_id.crate != local_crate ||
|
||||
(cx.reachable)(def_id.node) {
|
||||
w.write_char('"');
|
||||
w.write_str((cx.ds)(def_id));
|
||||
w.write_char('|');
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
enc_sty(w, cx, /*bad*/copy ty::get(t).sty);
|
||||
let end = w.tell();
|
||||
let len = end - pos;
|
||||
|
|
|
@ -143,13 +143,17 @@ pub fn log_fn_time(ccx: @CrateContext, +name: ~str, start: time::Timespec,
|
|||
ccx.stats.fn_times.push((name, elapsed));
|
||||
}
|
||||
|
||||
pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv,
|
||||
llty: TypeRef) -> ValueRef {
|
||||
pub fn decl_fn(llmod: ModuleRef,
|
||||
name: &str,
|
||||
cc: lib::llvm::CallConv,
|
||||
llty: TypeRef)
|
||||
-> ValueRef {
|
||||
let llfn: ValueRef = str::as_c_str(name, |buf| {
|
||||
unsafe {
|
||||
llvm::LLVMGetOrInsertFunction(llmod, buf, llty)
|
||||
}
|
||||
});
|
||||
|
||||
lib::llvm::SetFunctionCallConv(llfn, cc);
|
||||
return llfn;
|
||||
}
|
||||
|
@ -406,24 +410,24 @@ pub fn set_optimize_for_size(f: ValueRef) {
|
|||
unsafe {
|
||||
llvm::LLVMAddFunctionAttr(f,
|
||||
lib::llvm::OptimizeForSizeAttribute
|
||||
as c_ulonglong,
|
||||
0u as c_ulonglong);
|
||||
as c_uint,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_no_inline(f: ValueRef) {
|
||||
unsafe {
|
||||
llvm::LLVMAddFunctionAttr(f,
|
||||
lib::llvm::NoInlineAttribute as c_ulonglong,
|
||||
0u as c_ulonglong);
|
||||
lib::llvm::NoInlineAttribute as c_uint,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_no_unwind(f: ValueRef) {
|
||||
unsafe {
|
||||
llvm::LLVMAddFunctionAttr(f,
|
||||
lib::llvm::NoUnwindAttribute as c_ulonglong,
|
||||
0u as c_ulonglong);
|
||||
lib::llvm::NoUnwindAttribute as c_uint,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,15 +436,16 @@ pub fn set_no_unwind(f: ValueRef) {
|
|||
pub fn set_uwtable(f: ValueRef) {
|
||||
unsafe {
|
||||
llvm::LLVMAddFunctionAttr(f,
|
||||
lib::llvm::UWTableAttribute as c_ulonglong,
|
||||
0u as c_ulonglong);
|
||||
lib::llvm::UWTableAttribute as c_uint,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_inline_hint(f: ValueRef) {
|
||||
unsafe {
|
||||
llvm::LLVMAddFunctionAttr(f, lib::llvm::InlineHintAttribute
|
||||
as c_ulonglong, 0u as c_ulonglong);
|
||||
llvm::LLVMAddFunctionAttr(f,
|
||||
lib::llvm::InlineHintAttribute as c_uint,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -456,14 +461,15 @@ pub fn set_inline_hint_if_appr(attrs: &[ast::attribute],
|
|||
|
||||
pub fn set_always_inline(f: ValueRef) {
|
||||
unsafe {
|
||||
llvm::LLVMAddFunctionAttr(f, lib::llvm::AlwaysInlineAttribute
|
||||
as c_ulonglong, 0u as c_ulonglong);
|
||||
llvm::LLVMAddFunctionAttr(f,
|
||||
lib::llvm::AlwaysInlineAttribute as c_uint,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_custom_stack_growth_fn(f: ValueRef) {
|
||||
pub fn set_fixed_stack_segment(f: ValueRef) {
|
||||
unsafe {
|
||||
llvm::LLVMAddFunctionAttr(f, 0u as c_ulonglong, 1u as c_ulonglong);
|
||||
llvm::LLVMAddFunctionAttr(f, 0, 1 << (39 - 32));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,17 +489,25 @@ pub fn note_unique_llvm_symbol(ccx: @CrateContext, sym: @~str) {
|
|||
}
|
||||
|
||||
|
||||
pub fn get_res_dtor(ccx: @CrateContext, did: ast::def_id,
|
||||
parent_id: ast::def_id, substs: &[ty::t])
|
||||
-> ValueRef {
|
||||
pub fn get_res_dtor(ccx: @CrateContext,
|
||||
did: ast::def_id,
|
||||
parent_id: ast::def_id,
|
||||
substs: &[ty::t])
|
||||
-> ValueRef {
|
||||
let _icx = ccx.insn_ctxt("trans_res_dtor");
|
||||
if !substs.is_empty() {
|
||||
let did = if did.crate != ast::local_crate {
|
||||
inline::maybe_instantiate_inline(ccx, did, true)
|
||||
} else { did };
|
||||
} else {
|
||||
did
|
||||
};
|
||||
assert!(did.crate == ast::local_crate);
|
||||
let (val, _) =
|
||||
monomorphize::monomorphic_fn(ccx, did, substs, None, None, None);
|
||||
let (val, _) = monomorphize::monomorphic_fn(ccx,
|
||||
did,
|
||||
substs,
|
||||
None,
|
||||
None,
|
||||
None);
|
||||
|
||||
val
|
||||
} else if did.crate == ast::local_crate {
|
||||
|
@ -501,11 +515,16 @@ pub fn get_res_dtor(ccx: @CrateContext, did: ast::def_id,
|
|||
} else {
|
||||
let tcx = ccx.tcx;
|
||||
let name = csearch::get_symbol(ccx.sess.cstore, did);
|
||||
let class_ty = ty::subst_tps(tcx, substs, None,
|
||||
ty::lookup_item_type(tcx, parent_id).ty);
|
||||
let class_ty = ty::subst_tps(tcx,
|
||||
substs,
|
||||
None,
|
||||
ty::lookup_item_type(tcx, parent_id).ty);
|
||||
let llty = type_of_dtor(ccx, class_ty);
|
||||
let name = name.to_managed(); // :-(
|
||||
get_extern_fn(ccx.externs, ccx.llmod, name, lib::llvm::CCallConv,
|
||||
get_extern_fn(ccx.externs,
|
||||
ccx.llmod,
|
||||
name,
|
||||
lib::llvm::CCallConv,
|
||||
llty)
|
||||
}
|
||||
}
|
||||
|
@ -809,9 +828,12 @@ pub fn trans_external_path(ccx: @CrateContext, did: ast::def_id, t: ty::t)
|
|||
};
|
||||
}
|
||||
|
||||
pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block {
|
||||
pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef])
|
||||
-> (ValueRef, block) {
|
||||
let _icx = bcx.insn_ctxt("invoke_");
|
||||
if bcx.unreachable { return bcx; }
|
||||
if bcx.unreachable {
|
||||
return (C_null(T_i8()), bcx);
|
||||
}
|
||||
|
||||
match bcx.node_info {
|
||||
None => debug!("invoke at ???"),
|
||||
|
@ -831,8 +853,12 @@ pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block {
|
|||
}
|
||||
}
|
||||
let normal_bcx = sub_block(bcx, ~"normal return");
|
||||
Invoke(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx));
|
||||
return normal_bcx;
|
||||
let llresult = Invoke(bcx,
|
||||
llfn,
|
||||
llargs,
|
||||
normal_bcx.llbb,
|
||||
get_landing_pad(bcx));
|
||||
return (llresult, normal_bcx);
|
||||
} else {
|
||||
unsafe {
|
||||
debug!("calling %x at %x",
|
||||
|
@ -842,8 +868,8 @@ pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block {
|
|||
debug!("arg: %x", ::core::cast::transmute(llarg));
|
||||
}
|
||||
}
|
||||
Call(bcx, llfn, llargs);
|
||||
return bcx;
|
||||
let llresult = Call(bcx, llfn, llargs);
|
||||
return (llresult, bcx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1574,6 +1600,18 @@ pub fn mk_standard_basic_blocks(llfn: ValueRef) -> BasicBlocks {
|
|||
}
|
||||
}
|
||||
|
||||
// Creates and returns space for, or returns the argument representing, the
|
||||
// slot where the return value of the function must go.
|
||||
pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef {
|
||||
unsafe {
|
||||
if !ty::type_is_immediate(output_type) {
|
||||
llvm::LLVMGetParam(fcx.llfn, 0)
|
||||
} else {
|
||||
let lloutputtype = type_of::type_of(*fcx.ccx, output_type);
|
||||
alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NB: must keep 4 fns in sync:
|
||||
//
|
||||
|
@ -1585,10 +1623,11 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
|
|||
+path: path,
|
||||
llfndecl: ValueRef,
|
||||
id: ast::node_id,
|
||||
output_type: ty::t,
|
||||
impl_id: Option<ast::def_id>,
|
||||
param_substs: Option<@param_substs>,
|
||||
sp: Option<span>) -> fn_ctxt
|
||||
{
|
||||
sp: Option<span>)
|
||||
-> fn_ctxt {
|
||||
for param_substs.each |p| { p.validate(); }
|
||||
|
||||
debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \
|
||||
|
@ -1599,16 +1638,26 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
|
|||
param_substs.repr(ccx.tcx));
|
||||
|
||||
let llbbs = mk_standard_basic_blocks(llfndecl);
|
||||
return @mut fn_ctxt_ {
|
||||
|
||||
let substd_output_type = match param_substs {
|
||||
None => output_type,
|
||||
Some(substs) => {
|
||||
ty::subst_tps(ccx.tcx, substs.tys, substs.self_ty, output_type)
|
||||
}
|
||||
};
|
||||
let is_immediate = ty::type_is_immediate(substd_output_type);
|
||||
|
||||
let fcx = @mut fn_ctxt_ {
|
||||
llfn: llfndecl,
|
||||
llenv: unsafe { llvm::LLVMGetParam(llfndecl, 1u as c_uint) },
|
||||
llretptr: unsafe { llvm::LLVMGetParam(llfndecl, 0u as c_uint) },
|
||||
llretptr: None,
|
||||
llstaticallocas: llbbs.sa,
|
||||
llloadenv: None,
|
||||
llreturn: llbbs.rt,
|
||||
llself: None,
|
||||
personality: None,
|
||||
loop_ret: None,
|
||||
has_immediate_return_value: is_immediate,
|
||||
llargs: @mut HashMap::new(),
|
||||
lllocals: @mut HashMap::new(),
|
||||
llupvars: @mut HashMap::new(),
|
||||
|
@ -1619,14 +1668,18 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
|
|||
path: path,
|
||||
ccx: @ccx
|
||||
};
|
||||
|
||||
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
|
||||
fcx
|
||||
}
|
||||
|
||||
pub fn new_fn_ctxt(ccx: @CrateContext,
|
||||
+path: path,
|
||||
llfndecl: ValueRef,
|
||||
output_type: ty::t,
|
||||
sp: Option<span>)
|
||||
-> fn_ctxt {
|
||||
return new_fn_ctxt_w_id(ccx, path, llfndecl, -1, None, None, sp);
|
||||
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, None, sp)
|
||||
}
|
||||
|
||||
// NB: must keep 4 fns in sync:
|
||||
|
@ -1645,7 +1698,8 @@ pub fn new_fn_ctxt(ccx: @CrateContext,
|
|||
// field of the fn_ctxt with
|
||||
pub fn create_llargs_for_fn_args(cx: fn_ctxt,
|
||||
ty_self: self_arg,
|
||||
args: &[ast::arg]) -> ~[ValueRef] {
|
||||
args: &[ast::arg])
|
||||
-> ~[ValueRef] {
|
||||
let _icx = cx.insn_ctxt("create_llargs_for_fn_args");
|
||||
|
||||
match ty_self {
|
||||
|
@ -1751,8 +1805,19 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
|
|||
pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) {
|
||||
let _icx = fcx.insn_ctxt("finish_fn");
|
||||
tie_up_header_blocks(fcx, lltop);
|
||||
build_return_block(fcx);
|
||||
}
|
||||
|
||||
// Builds the return block for a function.
|
||||
pub fn build_return_block(fcx: fn_ctxt) {
|
||||
let ret_cx = raw_block(fcx, false, fcx.llreturn);
|
||||
RetVoid(ret_cx);
|
||||
|
||||
// Return the value if this function immediate; otherwise, return void.
|
||||
if fcx.has_immediate_return_value {
|
||||
Ret(ret_cx, Load(ret_cx, fcx.llretptr.get()))
|
||||
} else {
|
||||
RetVoid(ret_cx)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
|
||||
|
@ -1782,6 +1847,8 @@ pub fn trans_closure(ccx: @CrateContext,
|
|||
param_substs: Option<@param_substs>,
|
||||
id: ast::node_id,
|
||||
impl_id: Option<ast::def_id>,
|
||||
attributes: &[ast::attribute],
|
||||
output_type: ty::t,
|
||||
maybe_load_env: &fn(fn_ctxt),
|
||||
finish: &fn(block)) {
|
||||
ccx.stats.n_closures += 1;
|
||||
|
@ -1792,10 +1859,21 @@ pub fn trans_closure(ccx: @CrateContext,
|
|||
param_substs.repr(ccx.tcx));
|
||||
|
||||
// Set up arguments to the function.
|
||||
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, impl_id, param_substs,
|
||||
Some(body.span));
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, ty_self,
|
||||
decl.inputs);
|
||||
let fcx = new_fn_ctxt_w_id(ccx,
|
||||
path,
|
||||
llfndecl,
|
||||
id,
|
||||
output_type,
|
||||
impl_id,
|
||||
param_substs,
|
||||
Some(body.span));
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, ty_self, decl.inputs);
|
||||
|
||||
// Set the fixed stack segment flag if necessary.
|
||||
if attr::attrs_contains_name(attributes, "fixed_stack_segment") {
|
||||
set_no_inline(fcx.llfn);
|
||||
set_fixed_stack_segment(fcx.llfn);
|
||||
}
|
||||
|
||||
// Set GC for function.
|
||||
if ccx.sess.opts.gc {
|
||||
|
@ -1828,7 +1906,8 @@ pub fn trans_closure(ccx: @CrateContext,
|
|||
{
|
||||
bcx = controlflow::trans_block(bcx, body, expr::Ignore);
|
||||
} else {
|
||||
bcx = controlflow::trans_block(bcx, body, expr::SaveIn(fcx.llretptr));
|
||||
let dest = expr::SaveIn(fcx.llretptr.get());
|
||||
bcx = controlflow::trans_block(bcx, body, dest);
|
||||
}
|
||||
|
||||
finish(bcx);
|
||||
|
@ -1848,7 +1927,8 @@ pub fn trans_fn(ccx: @CrateContext,
|
|||
ty_self: self_arg,
|
||||
param_substs: Option<@param_substs>,
|
||||
id: ast::node_id,
|
||||
impl_id: Option<ast::def_id>) {
|
||||
impl_id: Option<ast::def_id>,
|
||||
attrs: &[ast::attribute]) {
|
||||
let do_time = ccx.sess.trans_stats();
|
||||
let start = if do_time { time::get_time() }
|
||||
else { time::Timespec::new(0, 0) };
|
||||
|
@ -1858,8 +1938,18 @@ pub fn trans_fn(ccx: @CrateContext,
|
|||
let _icx = ccx.insn_ctxt("trans_fn");
|
||||
ccx.stats.n_fns += 1;
|
||||
let the_path_str = path_str(ccx.sess, path);
|
||||
trans_closure(ccx, path, decl, body, llfndecl, ty_self,
|
||||
param_substs, id, impl_id,
|
||||
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
|
||||
trans_closure(ccx,
|
||||
path,
|
||||
decl,
|
||||
body,
|
||||
llfndecl,
|
||||
ty_self,
|
||||
param_substs,
|
||||
id,
|
||||
impl_id,
|
||||
attrs,
|
||||
output_type,
|
||||
|fcx| {
|
||||
if ccx.sess.opts.extra_debuginfo
|
||||
&& fcx_has_nonzero_span(fcx) {
|
||||
|
@ -1894,26 +1984,39 @@ pub fn trans_enum_variant(ccx: @CrateContext,
|
|||
id: varg.id,
|
||||
}
|
||||
};
|
||||
let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, variant.node.id, None,
|
||||
param_substs, None);
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
|
||||
|
||||
let ty_param_substs = match param_substs {
|
||||
Some(ref substs) => { copy substs.tys }
|
||||
None => ~[]
|
||||
};
|
||||
let enum_ty = ty::subst_tps(ccx.tcx,
|
||||
ty_param_substs,
|
||||
None,
|
||||
ty::node_id_to_type(ccx.tcx, enum_id));
|
||||
let fcx = new_fn_ctxt_w_id(ccx,
|
||||
~[],
|
||||
llfndecl,
|
||||
variant.node.id,
|
||||
enum_ty,
|
||||
None,
|
||||
param_substs,
|
||||
None);
|
||||
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
|
||||
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
|
||||
let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id));
|
||||
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
|
||||
|
||||
// XXX is there a better way to reconstruct the ty::t?
|
||||
let enum_ty = ty::subst_tps(ccx.tcx, ty_param_substs, None,
|
||||
ty::node_id_to_type(ccx.tcx, enum_id));
|
||||
let repr = adt::represent_type(ccx, enum_ty);
|
||||
|
||||
adt::trans_start_init(bcx, repr, fcx.llretptr, disr);
|
||||
adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr);
|
||||
for vec::eachi(args) |i, va| {
|
||||
let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr,
|
||||
disr, i);
|
||||
let lldestptr = adt::trans_field_ptr(bcx,
|
||||
repr,
|
||||
fcx.llretptr.get(),
|
||||
disr,
|
||||
i);
|
||||
|
||||
// If this argument to this function is a enum, it'll have come in to
|
||||
// this function as an opaque blob due to the way that type_of()
|
||||
|
@ -1951,21 +2054,6 @@ pub fn trans_tuple_struct(ccx: @CrateContext,
|
|||
}
|
||||
};
|
||||
|
||||
let fcx = new_fn_ctxt_w_id(ccx,
|
||||
~[],
|
||||
llfndecl,
|
||||
ctor_id,
|
||||
None,
|
||||
param_substs,
|
||||
None);
|
||||
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
|
||||
|
||||
let bcx = top_scope_block(fcx, None);
|
||||
let lltop = bcx.llbb;
|
||||
let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
|
||||
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
|
||||
|
||||
// XXX is there a better way to reconstruct the ty::t?
|
||||
let ty_param_substs = match param_substs {
|
||||
Some(ref substs) => { copy substs.tys }
|
||||
|
@ -1979,10 +2067,31 @@ pub fn trans_tuple_struct(ccx: @CrateContext,
|
|||
return type %s",
|
||||
ty_to_str(ccx.tcx, ctor_ty)))
|
||||
};
|
||||
|
||||
let fcx = new_fn_ctxt_w_id(ccx,
|
||||
~[],
|
||||
llfndecl,
|
||||
ctor_id,
|
||||
tup_ty,
|
||||
None,
|
||||
param_substs,
|
||||
None);
|
||||
|
||||
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
|
||||
|
||||
let bcx = top_scope_block(fcx, None);
|
||||
let lltop = bcx.llbb;
|
||||
let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
|
||||
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
|
||||
|
||||
let repr = adt::represent_type(ccx, tup_ty);
|
||||
|
||||
for fields.eachi |i, field| {
|
||||
let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr, 0, i);
|
||||
let lldestptr = adt::trans_field_ptr(bcx,
|
||||
repr,
|
||||
fcx.llretptr.get(),
|
||||
0,
|
||||
i);
|
||||
let llarg = match *fcx.llargs.get(&field.node.id) {
|
||||
local_mem(x) => x,
|
||||
_ => {
|
||||
|
@ -2032,8 +2141,16 @@ pub fn trans_struct_dtor(ccx: @CrateContext,
|
|||
}
|
||||
/* Translate the dtor body */
|
||||
let decl = ast_util::dtor_dec();
|
||||
trans_fn(ccx, path, &decl, body, lldecl,
|
||||
impl_self(class_ty), psubsts, dtor_id, None);
|
||||
trans_fn(ccx,
|
||||
path,
|
||||
&decl,
|
||||
body,
|
||||
lldecl,
|
||||
impl_self(class_ty),
|
||||
psubsts,
|
||||
dtor_id,
|
||||
None,
|
||||
[]);
|
||||
lldecl
|
||||
}
|
||||
|
||||
|
@ -2074,15 +2191,24 @@ pub fn trans_item(ccx: @CrateContext, item: ast::item) {
|
|||
if purity == ast::extern_fn {
|
||||
let llfndecl = get_item_val(ccx, item.id);
|
||||
foreign::trans_foreign_fn(ccx,
|
||||
vec::append(
|
||||
/*bad*/copy *path,
|
||||
~[path_name(item.ident)]),
|
||||
decl, body, llfndecl, item.id);
|
||||
vec::append(/*bad*/copy *path,
|
||||
~[path_name(item.ident)]),
|
||||
decl,
|
||||
body,
|
||||
llfndecl,
|
||||
item.id);
|
||||
} else if !generics.is_type_parameterized() {
|
||||
let llfndecl = get_item_val(ccx, item.id);
|
||||
trans_fn(ccx,
|
||||
vec::append(/*bad*/copy *path, ~[path_name(item.ident)]),
|
||||
decl, body, llfndecl, no_self, None, item.id, None);
|
||||
decl,
|
||||
body,
|
||||
llfndecl,
|
||||
no_self,
|
||||
None,
|
||||
item.id,
|
||||
None,
|
||||
item.attrs);
|
||||
} else {
|
||||
for body.node.stmts.each |stmt| {
|
||||
match stmt.node {
|
||||
|
@ -2187,7 +2313,7 @@ pub fn register_fn_fuller(ccx: @CrateContext,
|
|||
node_type: ty::t,
|
||||
cc: lib::llvm::CallConv,
|
||||
llfty: TypeRef)
|
||||
-> ValueRef {
|
||||
-> ValueRef {
|
||||
debug!("register_fn_fuller creating fn for item %d with path %s",
|
||||
node_id,
|
||||
ast_map::path_to_str(path, ccx.sess.parse_sess.interner));
|
||||
|
@ -2207,7 +2333,9 @@ pub fn register_fn_fuller(ccx: @CrateContext,
|
|||
(!*ccx.sess.building_library ||
|
||||
(*ccx.sess.building_library &&
|
||||
ccx.sess.targ_cfg.os == session::os_android));
|
||||
if is_entry { create_entry_wrapper(ccx, sp, llfn); }
|
||||
if is_entry {
|
||||
create_entry_wrapper(ccx, sp, llfn);
|
||||
}
|
||||
llfn
|
||||
}
|
||||
|
||||
|
@ -2236,23 +2364,26 @@ pub fn create_entry_wrapper(ccx: @CrateContext,
|
|||
let llfdecl = decl_fn(ccx.llmod, ~"_rust_main",
|
||||
lib::llvm::CCallConv, llfty);
|
||||
|
||||
let fcx = new_fn_ctxt(ccx, ~[], llfdecl, None);
|
||||
let fcx = new_fn_ctxt(ccx, ~[], llfdecl, nt, None);
|
||||
|
||||
let bcx = top_scope_block(fcx, None);
|
||||
let lltop = bcx.llbb;
|
||||
|
||||
// Call main.
|
||||
let lloutputarg = unsafe { llvm::LLVMGetParam(llfdecl, 0 as c_uint) };
|
||||
let lloutputarg = C_null(T_ptr(T_i8()));
|
||||
let llenvarg = unsafe { llvm::LLVMGetParam(llfdecl, 1 as c_uint) };
|
||||
let mut args = ~[lloutputarg, llenvarg];
|
||||
Call(bcx, main_llfn, args);
|
||||
let llresult = Call(bcx, main_llfn, args);
|
||||
Store(bcx, llresult, fcx.llretptr.get());
|
||||
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
return llfdecl;
|
||||
}
|
||||
|
||||
fn create_entry_fn(ccx: @CrateContext, rust_main: ValueRef, use_start_lang_item:bool) {
|
||||
fn create_entry_fn(ccx: @CrateContext,
|
||||
rust_main: ValueRef,
|
||||
use_start_lang_item: bool) {
|
||||
let llfty = T_fn(~[ccx.int_type, T_ptr(T_ptr(T_i8()))], ccx.int_type);
|
||||
|
||||
// FIXME #4404 android JNI hacks
|
||||
|
@ -2273,58 +2404,70 @@ pub fn create_entry_wrapper(ccx: @CrateContext,
|
|||
let bld = ccx.builder.B;
|
||||
unsafe {
|
||||
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
|
||||
}
|
||||
|
||||
let retptr = unsafe {
|
||||
llvm::LLVMBuildAlloca(bld, ccx.int_type, noname())
|
||||
};
|
||||
|
||||
let crate_map = ccx.crate_map;
|
||||
let opaque_crate_map = unsafe {llvm::LLVMBuildPointerCast(
|
||||
bld, crate_map, T_ptr(T_i8()), noname())};
|
||||
|
||||
let (start_fn, args) = if use_start_lang_item {
|
||||
let crate_map = ccx.crate_map;
|
||||
let start_def_id = ccx.tcx.lang_items.start_fn();
|
||||
let start_fn = if start_def_id.crate == ast::local_crate {
|
||||
ccx.sess.bug(~"start lang item is never in the local crate")
|
||||
} else {
|
||||
let start_fn_type = csearch::get_type(ccx.tcx,
|
||||
start_def_id).ty;
|
||||
start_def_id).ty;
|
||||
trans_external_path(ccx, start_def_id, start_fn_type)
|
||||
};
|
||||
|
||||
let args = unsafe {
|
||||
let opaque_rust_main = llvm::LLVMBuildPointerCast(
|
||||
bld, rust_main, T_ptr(T_i8()), noname());
|
||||
let retptr = llvm::LLVMBuildAlloca(bld, T_i8(), noname());
|
||||
|
||||
~[
|
||||
retptr,
|
||||
C_null(T_opaque_box_ptr(ccx)),
|
||||
opaque_rust_main,
|
||||
llvm::LLVMGetParam(llfn, 0 as c_uint),
|
||||
llvm::LLVMGetParam(llfn, 1 as c_uint),
|
||||
opaque_crate_map
|
||||
]
|
||||
};
|
||||
(start_fn, args)
|
||||
} else {
|
||||
debug!("using user-defined start fn");
|
||||
let args = unsafe {
|
||||
~[ retptr,
|
||||
C_null(T_opaque_box_ptr(ccx)),
|
||||
llvm::LLVMGetParam(llfn, 0 as c_uint),
|
||||
llvm::LLVMGetParam(llfn, 1 as c_uint),
|
||||
opaque_crate_map
|
||||
]
|
||||
let crate_map = ccx.crate_map;
|
||||
let opaque_crate_map = llvm::LLVMBuildPointerCast(bld,
|
||||
crate_map,
|
||||
T_ptr(T_i8()),
|
||||
noname());
|
||||
|
||||
let (start_fn, args) = if use_start_lang_item {
|
||||
let start_def_id = ccx.tcx.lang_items.start_fn();
|
||||
let start_fn = if start_def_id.crate == ast::local_crate {
|
||||
ccx.sess.bug(~"start lang item is never in the local \
|
||||
crate")
|
||||
} else {
|
||||
let start_fn_type = csearch::get_type(ccx.tcx,
|
||||
start_def_id).ty;
|
||||
trans_external_path(ccx, start_def_id, start_fn_type)
|
||||
};
|
||||
|
||||
let args = {
|
||||
let opaque_rust_main = llvm::LLVMBuildPointerCast(
|
||||
bld, rust_main, T_ptr(T_i8()), noname());
|
||||
|
||||
~[
|
||||
retptr,
|
||||
C_null(T_opaque_box_ptr(ccx)),
|
||||
opaque_rust_main,
|
||||
llvm::LLVMGetParam(llfn, 0),
|
||||
llvm::LLVMGetParam(llfn, 1),
|
||||
opaque_crate_map
|
||||
]
|
||||
};
|
||||
(start_fn, args)
|
||||
} else {
|
||||
debug!("using user-defined start fn");
|
||||
let args = {
|
||||
~[
|
||||
retptr,
|
||||
C_null(T_opaque_box_ptr(ccx)),
|
||||
llvm::LLVMGetParam(llfn, 0 as c_uint),
|
||||
llvm::LLVMGetParam(llfn, 1 as c_uint),
|
||||
opaque_crate_map
|
||||
]
|
||||
};
|
||||
|
||||
(rust_main, args)
|
||||
};
|
||||
|
||||
(rust_main, args)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
llvm::LLVMBuildCall(bld, start_fn, vec::raw::to_ptr(args),
|
||||
args.len() as c_uint, noname());
|
||||
let result = llvm::LLVMBuildLoad(bld, retptr, noname());
|
||||
let result = llvm::LLVMBuildCall(bld,
|
||||
start_fn,
|
||||
&args[0],
|
||||
args.len() as c_uint,
|
||||
noname());
|
||||
llvm::LLVMBuildRet(bld, result);
|
||||
}
|
||||
}
|
||||
|
@ -2395,7 +2538,6 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef {
|
|||
match ccx.item_vals.find(&id) {
|
||||
Some(&v) => v,
|
||||
None => {
|
||||
|
||||
let mut exprt = false;
|
||||
let val = match *ccx.tcx.items.get(&id) {
|
||||
ast_map::node_item(i, pth) => {
|
||||
|
@ -2487,10 +2629,10 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef {
|
|||
assert!(!ty::type_has_params(class_ty));
|
||||
let lldty = unsafe {
|
||||
T_fn(~[
|
||||
T_ptr(type_of(ccx, ty::mk_nil(tcx))),
|
||||
T_ptr(T_i8()),
|
||||
T_ptr(type_of(ccx, class_ty))
|
||||
],
|
||||
llvm::LLVMVoidType())
|
||||
T_nil())
|
||||
};
|
||||
let s = get_dtor_symbol(ccx, /*bad*/copy *pt, dt.node.id, None);
|
||||
|
||||
|
|
|
@ -181,9 +181,15 @@ pub fn noname() -> *libc::c_char {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn Invoke(cx: block, Fn: ValueRef, Args: &[ValueRef],
|
||||
Then: BasicBlockRef, Catch: BasicBlockRef) {
|
||||
if cx.unreachable { return; }
|
||||
pub fn Invoke(cx: block,
|
||||
Fn: ValueRef,
|
||||
Args: &[ValueRef],
|
||||
Then: BasicBlockRef,
|
||||
Catch: BasicBlockRef)
|
||||
-> ValueRef {
|
||||
if cx.unreachable {
|
||||
return C_null(T_i8());
|
||||
}
|
||||
check_not_terminated(cx);
|
||||
terminate(cx, "Invoke");
|
||||
debug!("Invoke(%s with arguments (%s))",
|
||||
|
@ -193,9 +199,13 @@ pub fn Invoke(cx: block, Fn: ValueRef, Args: &[ValueRef],
|
|||
~", "));
|
||||
unsafe {
|
||||
count_insn(cx, "invoke");
|
||||
llvm::LLVMBuildInvoke(B(cx), Fn, vec::raw::to_ptr(Args),
|
||||
Args.len() as c_uint, Then, Catch,
|
||||
noname());
|
||||
llvm::LLVMBuildInvoke(B(cx),
|
||||
Fn,
|
||||
vec::raw::to_ptr(Args),
|
||||
Args.len() as c_uint,
|
||||
Then,
|
||||
Catch,
|
||||
noname())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,16 +92,19 @@ pub impl FnType {
|
|||
return llargvals;
|
||||
}
|
||||
|
||||
fn build_shim_ret(&self, bcx: block,
|
||||
arg_tys: &[TypeRef], ret_def: bool,
|
||||
llargbundle: ValueRef, llretval: ValueRef) {
|
||||
fn build_shim_ret(&self,
|
||||
bcx: block,
|
||||
arg_tys: &[TypeRef],
|
||||
ret_def: bool,
|
||||
llargbundle: ValueRef,
|
||||
llretval: ValueRef) {
|
||||
for vec::eachi(self.attrs) |i, a| {
|
||||
match *a {
|
||||
option::Some(attr) => {
|
||||
unsafe {
|
||||
llvm::LLVMAddInstrAttribute(
|
||||
llretval, (i + 1u) as c_uint,
|
||||
attr as c_uint);
|
||||
llvm::LLVMAddInstrAttribute(llretval,
|
||||
(i + 1u) as c_uint,
|
||||
attr as c_uint);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
|
@ -125,8 +128,11 @@ pub impl FnType {
|
|||
};
|
||||
}
|
||||
|
||||
fn build_wrap_args(&self, bcx: block, ret_ty: TypeRef,
|
||||
llwrapfn: ValueRef, llargbundle: ValueRef) {
|
||||
fn build_wrap_args(&self,
|
||||
bcx: block,
|
||||
ret_ty: TypeRef,
|
||||
llwrapfn: ValueRef,
|
||||
llargbundle: ValueRef) {
|
||||
let mut atys = /*bad*/copy self.arg_tys;
|
||||
let mut attrs = /*bad*/copy self.attrs;
|
||||
let mut j = 0u;
|
||||
|
@ -161,22 +167,27 @@ pub impl FnType {
|
|||
store_inbounds(bcx, llretptr, llargbundle, [0u, n]);
|
||||
}
|
||||
|
||||
fn build_wrap_ret(&self, bcx: block,
|
||||
arg_tys: &[TypeRef], llargbundle: ValueRef) {
|
||||
fn build_wrap_ret(&self,
|
||||
bcx: block,
|
||||
arg_tys: &[TypeRef],
|
||||
llargbundle: ValueRef) {
|
||||
unsafe {
|
||||
if llvm::LLVMGetTypeKind(self.ret_ty.ty) == Void {
|
||||
RetVoid(bcx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
let n = vec::len(arg_tys);
|
||||
let llretval = load_inbounds(bcx, llargbundle, ~[0u, n]);
|
||||
|
||||
let llretval = load_inbounds(bcx, llargbundle, ~[ 0, arg_tys.len() ]);
|
||||
let llretval = if self.ret_ty.cast {
|
||||
let retptr = BitCast(bcx, llretval, T_ptr(self.ret_ty.ty));
|
||||
Load(bcx, retptr)
|
||||
} else {
|
||||
Load(bcx, llretval)
|
||||
};
|
||||
Ret(bcx, llretval);
|
||||
let llretptr = BitCast(bcx,
|
||||
bcx.fcx.llretptr.get(),
|
||||
T_ptr(self.ret_ty.ty));
|
||||
Store(bcx, llretval, llretptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -314,11 +314,16 @@ pub fn trans_call(in_cx: block,
|
|||
args: CallArgs,
|
||||
id: ast::node_id,
|
||||
dest: expr::Dest)
|
||||
-> block {
|
||||
-> block {
|
||||
let _icx = in_cx.insn_ctxt("trans_call");
|
||||
trans_call_inner(
|
||||
in_cx, call_ex.info(), expr_ty(in_cx, f), node_id_type(in_cx, id),
|
||||
|cx| trans(cx, f), args, dest, DontAutorefArg)
|
||||
trans_call_inner(in_cx,
|
||||
call_ex.info(),
|
||||
expr_ty(in_cx, f),
|
||||
node_id_type(in_cx, id),
|
||||
|cx| trans(cx, f),
|
||||
args,
|
||||
dest,
|
||||
DontAutorefArg)
|
||||
}
|
||||
|
||||
pub fn trans_method_call(in_cx: block,
|
||||
|
@ -326,7 +331,7 @@ pub fn trans_method_call(in_cx: block,
|
|||
rcvr: @ast::expr,
|
||||
args: CallArgs,
|
||||
dest: expr::Dest)
|
||||
-> block {
|
||||
-> block {
|
||||
let _icx = in_cx.insn_ctxt("trans_method_call");
|
||||
debug!("trans_method_call(call_ex=%s, rcvr=%s)",
|
||||
call_ex.repr(in_cx.tcx()),
|
||||
|
@ -439,15 +444,15 @@ pub fn body_contains_ret(body: &ast::blk) -> bool {
|
|||
}
|
||||
|
||||
// See [Note-arg-mode]
|
||||
pub fn trans_call_inner(
|
||||
++in_cx: block,
|
||||
call_info: Option<NodeInfo>,
|
||||
fn_expr_ty: ty::t,
|
||||
ret_ty: ty::t,
|
||||
get_callee: &fn(block) -> Callee,
|
||||
args: CallArgs,
|
||||
dest: expr::Dest,
|
||||
autoref_arg: AutorefArg) -> block {
|
||||
pub fn trans_call_inner(++in_cx: block,
|
||||
call_info: Option<NodeInfo>,
|
||||
fn_expr_ty: ty::t,
|
||||
ret_ty: ty::t,
|
||||
get_callee: &fn(block) -> Callee,
|
||||
args: CallArgs,
|
||||
dest: expr::Dest,
|
||||
autoref_arg: AutorefArg)
|
||||
-> block {
|
||||
do base::with_scope(in_cx, call_info, ~"call") |cx| {
|
||||
let ret_in_loop = match args {
|
||||
ArgExprs(args) => {
|
||||
|
@ -500,7 +505,15 @@ pub fn trans_call_inner(
|
|||
let llretslot = trans_ret_slot(bcx, fn_expr_ty, dest);
|
||||
|
||||
let mut llargs = ~[];
|
||||
llargs.push(llretslot);
|
||||
|
||||
if ty::type_is_immediate(ret_ty) {
|
||||
unsafe {
|
||||
llargs.push(llvm::LLVMGetUndef(T_ptr(T_i8())));
|
||||
}
|
||||
} else {
|
||||
llargs.push(llretslot);
|
||||
}
|
||||
|
||||
llargs.push(llenv);
|
||||
bcx = trans_args(bcx, args, fn_expr_ty,
|
||||
ret_flag, autoref_arg, &mut llargs);
|
||||
|
@ -527,17 +540,34 @@ pub fn trans_call_inner(
|
|||
// If the block is terminated, then one or more of the args
|
||||
// has type _|_. Since that means it diverges, the code for
|
||||
// the call itself is unreachable.
|
||||
bcx = base::invoke(bcx, llfn, llargs);
|
||||
match dest { // drop the value if it is not being saved.
|
||||
let (llresult, new_bcx) = base::invoke(bcx, llfn, llargs);
|
||||
bcx = new_bcx;
|
||||
|
||||
match dest {
|
||||
expr::Ignore => {
|
||||
// drop the value if it is not being saved.
|
||||
unsafe {
|
||||
if llvm::LLVMIsUndef(llretslot) != lib::llvm::True {
|
||||
bcx = glue::drop_ty(bcx, llretslot, ret_ty);
|
||||
if ty::type_is_immediate(ret_ty) {
|
||||
let llscratchptr = alloc_ty(bcx, ret_ty);
|
||||
Store(bcx, llresult, llscratchptr);
|
||||
bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
|
||||
} else {
|
||||
bcx = glue::drop_ty(bcx, llretslot, ret_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
expr::SaveIn(_) => { }
|
||||
expr::SaveIn(lldest) => {
|
||||
// If this is an immediate, store into the result location.
|
||||
// (If this was not an immediate, the result will already be
|
||||
// directly written into the output slot.)
|
||||
if ty::type_is_immediate(ret_ty) {
|
||||
Store(bcx, llresult, lldest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ty::type_is_bot(ret_ty) {
|
||||
Unreachable(bcx);
|
||||
} else if ret_in_loop {
|
||||
|
@ -545,7 +575,7 @@ pub fn trans_call_inner(
|
|||
bcx = do with_cond(bcx, ret_flag_result) |bcx| {
|
||||
for (copy bcx.fcx.loop_ret).each |&(flagptr, _)| {
|
||||
Store(bcx, C_bool(true), flagptr);
|
||||
Store(bcx, C_bool(false), bcx.fcx.llretptr);
|
||||
Store(bcx, C_bool(false), bcx.fcx.llretptr.get());
|
||||
}
|
||||
base::cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
|
||||
Unreachable(bcx);
|
||||
|
@ -562,11 +592,10 @@ pub enum CallArgs<'self> {
|
|||
ArgVals(&'self [ValueRef])
|
||||
}
|
||||
|
||||
pub fn trans_ret_slot(+bcx: block,
|
||||
+fn_ty: ty::t,
|
||||
+dest: expr::Dest) -> ValueRef
|
||||
{
|
||||
pub fn trans_ret_slot(+bcx: block, +fn_ty: ty::t, +dest: expr::Dest)
|
||||
-> ValueRef {
|
||||
let retty = ty::ty_fn_ret(fn_ty);
|
||||
|
||||
match dest {
|
||||
expr::SaveIn(dst) => dst,
|
||||
expr::Ignore => {
|
||||
|
|
|
@ -299,7 +299,7 @@ pub fn build_closure(bcx0: block,
|
|||
// the right thing):
|
||||
let ret_true = match bcx.fcx.loop_ret {
|
||||
Some((_, retptr)) => retptr,
|
||||
None => bcx.fcx.llretptr
|
||||
None => bcx.fcx.llretptr.get()
|
||||
};
|
||||
let ret_casted = PointerCast(bcx, ret_true, T_ptr(T_nil()));
|
||||
let ret_datum = Datum {val: ret_casted, ty: ty::mk_nil(tcx),
|
||||
|
@ -367,8 +367,7 @@ pub fn trans_expr_fn(bcx: block,
|
|||
outer_id: ast::node_id,
|
||||
user_id: ast::node_id,
|
||||
is_loop_body: Option<Option<ValueRef>>,
|
||||
dest: expr::Dest) -> block
|
||||
{
|
||||
dest: expr::Dest) -> block {
|
||||
/*!
|
||||
*
|
||||
* Translates the body of a closure expression.
|
||||
|
@ -400,7 +399,9 @@ pub fn trans_expr_fn(bcx: block,
|
|||
|
||||
let ccx = bcx.ccx();
|
||||
let fty = node_id_type(bcx, outer_id);
|
||||
|
||||
let llfnty = type_of_fn_from_ty(ccx, fty);
|
||||
|
||||
let sub_path = vec::append_one(/*bad*/copy bcx.fcx.path,
|
||||
path_name(special_idents::anon));
|
||||
// XXX: Bad copy.
|
||||
|
@ -409,6 +410,21 @@ pub fn trans_expr_fn(bcx: block,
|
|||
~"expr_fn");
|
||||
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
|
||||
|
||||
// Always mark inline if this is a loop body. This is important for
|
||||
// performance on many programs with tight loops.
|
||||
if is_loop_body.is_some() {
|
||||
set_always_inline(llfn);
|
||||
} else {
|
||||
// Can't hurt.
|
||||
set_inline_hint(llfn);
|
||||
}
|
||||
|
||||
let real_return_type = if is_loop_body.is_some() {
|
||||
ty::mk_bool(bcx.tcx())
|
||||
} else {
|
||||
ty::ty_fn_ret(fty)
|
||||
};
|
||||
|
||||
let Result {bcx: bcx, val: closure} = match sigil {
|
||||
ast::BorrowedSigil | ast::ManagedSigil | ast::OwnedSigil => {
|
||||
let cap_vars = *ccx.maps.capture_map.get(&user_id);
|
||||
|
@ -416,14 +432,24 @@ pub fn trans_expr_fn(bcx: block,
|
|||
None => None};
|
||||
let ClosureResult {llbox, cdata_ty, bcx}
|
||||
= build_closure(bcx, cap_vars, sigil, ret_handle);
|
||||
trans_closure(ccx, sub_path, decl,
|
||||
body, llfn, no_self,
|
||||
/*bad*/ copy bcx.fcx.param_substs, user_id, None,
|
||||
trans_closure(ccx,
|
||||
sub_path,
|
||||
decl,
|
||||
body,
|
||||
llfn,
|
||||
no_self,
|
||||
/*bad*/ copy bcx.fcx.param_substs,
|
||||
user_id,
|
||||
None,
|
||||
[],
|
||||
real_return_type,
|
||||
|fcx| load_environment(fcx, cdata_ty, cap_vars,
|
||||
ret_handle.is_some(), sigil),
|
||||
|bcx| {
|
||||
if is_loop_body.is_some() {
|
||||
Store(bcx, C_bool(true), bcx.fcx.llretptr);
|
||||
Store(bcx,
|
||||
C_bool(true),
|
||||
bcx.fcx.llretptr.get());
|
||||
}
|
||||
});
|
||||
rslt(bcx, llbox)
|
||||
|
|
|
@ -291,10 +291,15 @@ pub struct fn_ctxt_ {
|
|||
// section of the executable we're generating.
|
||||
llfn: ValueRef,
|
||||
|
||||
// The two implicit arguments that arrive in the function we're creating.
|
||||
// For instance, foo(int, int) is really foo(ret*, env*, int, int).
|
||||
// The implicit environment argument that arrives in the function we're
|
||||
// creating.
|
||||
llenv: ValueRef,
|
||||
llretptr: ValueRef,
|
||||
|
||||
// The place to store the return value. If the return type is immediate,
|
||||
// this is an alloca in the function. Otherwise, it's the hidden first
|
||||
// parameter to the function. After function construction, this should
|
||||
// always be Some.
|
||||
llretptr: Option<ValueRef>,
|
||||
|
||||
// These elements: "hoisted basic blocks" containing
|
||||
// administrative activities that have to happen in only one place in
|
||||
|
@ -322,6 +327,11 @@ pub struct fn_ctxt_ {
|
|||
// for that (flagptr, retptr)
|
||||
loop_ret: Option<(ValueRef, ValueRef)>,
|
||||
|
||||
// True if this function has an immediate return value, false otherwise.
|
||||
// If this is false, the llretptr will alias the first argument of the
|
||||
// function.
|
||||
has_immediate_return_value: bool,
|
||||
|
||||
// Maps arguments to allocas created for them in llallocas.
|
||||
llargs: @mut HashMap<ast::node_id, local_val>,
|
||||
// Maps the def_ids for local variables to the allocas created for
|
||||
|
|
|
@ -274,7 +274,7 @@ pub fn trans_break_cont(bcx: block,
|
|||
Some(bcx) => bcx,
|
||||
// This is a return from a loop body block
|
||||
None => {
|
||||
Store(bcx, C_bool(!to_end), bcx.fcx.llretptr);
|
||||
Store(bcx, C_bool(!to_end), bcx.fcx.llretptr.get());
|
||||
cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
|
||||
Unreachable(bcx);
|
||||
return bcx;
|
||||
|
@ -303,14 +303,14 @@ pub fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block {
|
|||
// to false, return flag to true, and then store the value in the
|
||||
// parent's retptr.
|
||||
Store(bcx, C_bool(true), flagptr);
|
||||
Store(bcx, C_bool(false), bcx.fcx.llretptr);
|
||||
Store(bcx, C_bool(false), bcx.fcx.llretptr.get());
|
||||
match e {
|
||||
Some(x) => PointerCast(bcx, retptr,
|
||||
T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))),
|
||||
None => retptr
|
||||
}
|
||||
}
|
||||
None => bcx.fcx.llretptr
|
||||
None => bcx.fcx.llretptr.get()
|
||||
};
|
||||
match e {
|
||||
Some(x) => {
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
* value stored in the datum is indicated in the field `ty`.
|
||||
*
|
||||
* Generally speaking, you probably do not want to access the `val` field
|
||||
* unless you know what mode the value is in. Intead you should use one
|
||||
* unless you know what mode the value is in. Instead you should use one
|
||||
* of the following accessors:
|
||||
*
|
||||
* - `to_value_llval()` converts to by-value
|
||||
|
|
|
@ -624,10 +624,14 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
|
|||
let sigil = ty::ty_closure_sigil(expr_ty);
|
||||
match blk.node {
|
||||
ast::expr_fn_block(ref decl, ref body) => {
|
||||
return closure::trans_expr_fn(bcx, sigil,
|
||||
decl, body,
|
||||
expr.id, blk.id,
|
||||
Some(None), dest);
|
||||
return closure::trans_expr_fn(bcx,
|
||||
sigil,
|
||||
decl,
|
||||
body,
|
||||
expr.id,
|
||||
blk.id,
|
||||
Some(None),
|
||||
dest);
|
||||
}
|
||||
_ => {
|
||||
bcx.sess().impossible_case(
|
||||
|
@ -655,15 +659,30 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
|
|||
}
|
||||
ast::expr_binary(_, lhs, rhs) => {
|
||||
// if not overloaded, would be RvalueDatumExpr
|
||||
return trans_overloaded_op(bcx, expr, lhs, ~[rhs], dest);
|
||||
return trans_overloaded_op(bcx,
|
||||
expr,
|
||||
lhs,
|
||||
~[rhs],
|
||||
expr_ty(bcx, expr),
|
||||
dest);
|
||||
}
|
||||
ast::expr_unary(_, subexpr) => {
|
||||
// if not overloaded, would be RvalueDatumExpr
|
||||
return trans_overloaded_op(bcx, expr, subexpr, ~[], dest);
|
||||
return trans_overloaded_op(bcx,
|
||||
expr,
|
||||
subexpr,
|
||||
~[],
|
||||
expr_ty(bcx, expr),
|
||||
dest);
|
||||
}
|
||||
ast::expr_index(base, idx) => {
|
||||
// if not overloaded, would be RvalueDatumExpr
|
||||
return trans_overloaded_op(bcx, expr, base, ~[idx], dest);
|
||||
return trans_overloaded_op(bcx,
|
||||
expr,
|
||||
base,
|
||||
~[idx],
|
||||
expr_ty(bcx, expr),
|
||||
dest);
|
||||
}
|
||||
ast::expr_cast(val, _) => {
|
||||
match ty::get(node_id_type(bcx, expr.id)).sty {
|
||||
|
@ -1554,15 +1573,24 @@ fn trans_overloaded_op(bcx: block,
|
|||
expr: @ast::expr,
|
||||
rcvr: @ast::expr,
|
||||
+args: ~[@ast::expr],
|
||||
dest: Dest) -> block
|
||||
{
|
||||
ret_ty: ty::t,
|
||||
dest: Dest)
|
||||
-> block {
|
||||
let origin = *bcx.ccx().maps.method_map.get(&expr.id);
|
||||
let fty = node_id_type(bcx, expr.callee_id);
|
||||
return callee::trans_call_inner(
|
||||
bcx, expr.info(), fty,
|
||||
expr_ty(bcx, expr),
|
||||
|bcx| meth::trans_method_callee(bcx, expr.callee_id, rcvr, origin),
|
||||
callee::ArgExprs(args), dest, DoAutorefArg);
|
||||
callee::trans_call_inner(bcx,
|
||||
expr.info(),
|
||||
fty,
|
||||
ret_ty,
|
||||
|bcx| {
|
||||
meth::trans_method_callee(bcx,
|
||||
expr.callee_id,
|
||||
rcvr,
|
||||
origin)
|
||||
},
|
||||
callee::ArgExprs(args),
|
||||
dest,
|
||||
DoAutorefArg)
|
||||
}
|
||||
|
||||
fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef,
|
||||
|
@ -1697,7 +1725,11 @@ fn trans_assign_op(bcx: block,
|
|||
if bcx.ccx().maps.method_map.find(&expr.id).is_some() {
|
||||
// FIXME(#2528) evaluates the receiver twice!!
|
||||
let scratch = scratch_datum(bcx, dst_datum.ty, false);
|
||||
let bcx = trans_overloaded_op(bcx, expr, dst, ~[src],
|
||||
let bcx = trans_overloaded_op(bcx,
|
||||
expr,
|
||||
dst,
|
||||
~[src],
|
||||
dst_datum.ty,
|
||||
SaveIn(scratch.val));
|
||||
return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -499,7 +499,8 @@ pub fn trans_struct_drop(bcx: block,
|
|||
}
|
||||
|
||||
let self_arg = PointerCast(bcx, llval, params[1]);
|
||||
let args = ~[bcx.fcx.llretptr, self_arg];
|
||||
let args = ~[C_null(T_ptr(T_i8())), self_arg];
|
||||
|
||||
Call(bcx, dtor_addr, args);
|
||||
|
||||
// Drop the fields
|
||||
|
@ -575,9 +576,7 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
|
|||
build_return(bcx);
|
||||
}
|
||||
|
||||
pub fn decr_refcnt_maybe_free(bcx: block,
|
||||
box_ptr: ValueRef,
|
||||
t: ty::t)
|
||||
pub fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef, t: ty::t)
|
||||
-> block {
|
||||
let _icx = bcx.insn_ctxt("decr_refcnt_maybe_free");
|
||||
let ccx = bcx.ccx();
|
||||
|
@ -737,7 +736,7 @@ pub fn make_generic_glue_inner(ccx: @CrateContext,
|
|||
helper: glue_helper)
|
||||
-> ValueRef {
|
||||
let _icx = ccx.insn_ctxt("make_generic_glue_inner");
|
||||
let fcx = new_fn_ctxt(ccx, ~[], llfn, None);
|
||||
let fcx = new_fn_ctxt(ccx, ~[], llfn, ty::mk_nil(ccx.tcx), None);
|
||||
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
|
||||
ccx.stats.n_glues_created += 1u;
|
||||
// All glue functions take values passed *by alias*; this is a
|
||||
|
@ -756,8 +755,11 @@ pub fn make_generic_glue_inner(ccx: @CrateContext,
|
|||
return llfn;
|
||||
}
|
||||
|
||||
pub fn make_generic_glue(ccx: @CrateContext, t: ty::t, llfn: ValueRef,
|
||||
helper: glue_helper, name: &str)
|
||||
pub fn make_generic_glue(ccx: @CrateContext,
|
||||
t: ty::t,
|
||||
llfn: ValueRef,
|
||||
helper: glue_helper,
|
||||
name: &str)
|
||||
-> ValueRef {
|
||||
let _icx = ccx.insn_ctxt("make_generic_glue");
|
||||
if !ccx.sess.trans_stats() {
|
||||
|
@ -767,8 +769,10 @@ pub fn make_generic_glue(ccx: @CrateContext, t: ty::t, llfn: ValueRef,
|
|||
let start = time::get_time();
|
||||
let llval = make_generic_glue_inner(ccx, t, llfn, helper);
|
||||
let end = time::get_time();
|
||||
log_fn_time(ccx, fmt!("glue %s %s", name, ty_to_short_str(ccx.tcx, t)),
|
||||
start, end);
|
||||
log_fn_time(ccx,
|
||||
fmt!("glue %s %s", name, ty_to_short_str(ccx.tcx, t)),
|
||||
start,
|
||||
end);
|
||||
return llval;
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,8 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id,
|
|||
self_kind,
|
||||
None,
|
||||
mth.id,
|
||||
Some(impl_did));
|
||||
Some(impl_did),
|
||||
[]);
|
||||
}
|
||||
local_def(mth.id)
|
||||
}
|
||||
|
|
|
@ -137,7 +137,8 @@ pub fn trans_method(ccx: @CrateContext,
|
|||
self_arg,
|
||||
param_substs,
|
||||
method.id,
|
||||
Some(impl_id));
|
||||
Some(impl_id),
|
||||
[]);
|
||||
}
|
||||
|
||||
pub fn trans_self_arg(bcx: block,
|
||||
|
|
|
@ -195,7 +195,16 @@ pub fn monomorphic_fn(ccx: @CrateContext,
|
|||
}, _) => {
|
||||
let d = mk_lldecl();
|
||||
set_inline_hint_if_appr(/*bad*/copy i.attrs, d);
|
||||
trans_fn(ccx, pt, decl, body, d, no_self, psubsts, fn_id.node, None);
|
||||
trans_fn(ccx,
|
||||
pt,
|
||||
decl,
|
||||
body,
|
||||
d,
|
||||
no_self,
|
||||
psubsts,
|
||||
fn_id.node,
|
||||
None,
|
||||
[]);
|
||||
d
|
||||
}
|
||||
ast_map::node_item(*) => {
|
||||
|
|
|
@ -288,11 +288,15 @@ pub impl Reflector {
|
|||
let arg = unsafe {
|
||||
llvm::LLVMGetParam(llfdecl, first_real_arg as c_uint)
|
||||
};
|
||||
let fcx = new_fn_ctxt(ccx, ~[], llfdecl, None);
|
||||
let fcx = new_fn_ctxt(ccx,
|
||||
~[],
|
||||
llfdecl,
|
||||
ty::mk_uint(ccx.tcx),
|
||||
None);
|
||||
let bcx = top_scope_block(fcx, None);
|
||||
let arg = BitCast(bcx, arg, llptrty);
|
||||
let ret = adt::trans_get_discr(bcx, repr, arg);
|
||||
Store(bcx, ret, fcx.llretptr);
|
||||
Store(bcx, ret, fcx.llretptr.get());
|
||||
cleanup_and_Br(bcx, bcx, fcx.llreturn);
|
||||
finish_fn(fcx, bcx.llbb);
|
||||
llfdecl
|
||||
|
|
|
@ -39,20 +39,34 @@ pub fn type_of_explicit_args(ccx: @CrateContext,
|
|||
inputs.map(|arg| type_of_explicit_arg(ccx, arg))
|
||||
}
|
||||
|
||||
pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::arg],
|
||||
output: ty::t) -> TypeRef {
|
||||
pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::arg], output: ty::t)
|
||||
-> TypeRef {
|
||||
unsafe {
|
||||
let mut atys: ~[TypeRef] = ~[];
|
||||
|
||||
// Arg 0: Output pointer.
|
||||
atys.push(T_ptr(type_of(cx, output)));
|
||||
// (if the output type is non-immediate)
|
||||
let output_is_immediate = ty::type_is_immediate(output);
|
||||
let lloutputtype = type_of(cx, output);
|
||||
if !output_is_immediate {
|
||||
atys.push(T_ptr(lloutputtype));
|
||||
} else {
|
||||
// XXX: Eliminate this.
|
||||
atys.push(T_ptr(T_i8()));
|
||||
}
|
||||
|
||||
// Arg 1: Environment
|
||||
atys.push(T_opaque_box_ptr(cx));
|
||||
|
||||
// ... then explicit args.
|
||||
atys.push_all(type_of_explicit_args(cx, inputs));
|
||||
return T_fn(atys, llvm::LLVMVoidType());
|
||||
|
||||
// Use the output as the actual return value if it's immediate.
|
||||
if output_is_immediate {
|
||||
T_fn(atys, lloutputtype)
|
||||
} else {
|
||||
T_fn(atys, llvm::LLVMVoidType())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,11 +332,9 @@ pub fn llvm_type_name(cx: @CrateContext,
|
|||
}
|
||||
|
||||
pub fn type_of_dtor(ccx: @CrateContext, self_ty: ty::t) -> TypeRef {
|
||||
unsafe {
|
||||
T_fn(~[T_ptr(type_of(ccx, ty::mk_nil(ccx.tcx))), // output pointer
|
||||
T_ptr(type_of(ccx, self_ty))], // self arg
|
||||
llvm::LLVMVoidType())
|
||||
}
|
||||
T_fn(~[T_ptr(T_i8()), // output pointer
|
||||
T_ptr(type_of(ccx, self_ty))], // self arg
|
||||
T_nil())
|
||||
}
|
||||
|
||||
pub fn type_of_rooted(ccx: @CrateContext, t: ty::t) -> TypeRef {
|
||||
|
@ -336,5 +348,5 @@ pub fn type_of_glue_fn(ccx: @CrateContext, t: ty::t) -> TypeRef {
|
|||
let tydescpp = T_ptr(T_ptr(ccx.tydesc_type));
|
||||
let llty = T_ptr(type_of(ccx, t));
|
||||
return T_fn(~[T_ptr(T_nil()), T_ptr(T_nil()), tydescpp, llty],
|
||||
T_void());
|
||||
T_nil());
|
||||
}
|
||||
|
|
|
@ -133,7 +133,6 @@ impl to_bytes::IterBytes for creader_cache_key {
|
|||
|
||||
struct intern_key {
|
||||
sty: *sty,
|
||||
o_def_id: Option<ast::def_id>
|
||||
}
|
||||
|
||||
// NB: Do not replace this with #[deriving(Eq)]. The automatically-derived
|
||||
|
@ -142,7 +141,7 @@ struct intern_key {
|
|||
impl cmp::Eq for intern_key {
|
||||
fn eq(&self, other: &intern_key) -> bool {
|
||||
unsafe {
|
||||
*self.sty == *other.sty && self.o_def_id == other.o_def_id
|
||||
*self.sty == *other.sty
|
||||
}
|
||||
}
|
||||
fn ne(&self, other: &intern_key) -> bool {
|
||||
|
@ -153,7 +152,7 @@ impl cmp::Eq for intern_key {
|
|||
impl to_bytes::IterBytes for intern_key {
|
||||
fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
|
||||
unsafe {
|
||||
to_bytes::iter_bytes_2(&*self.sty, &self.o_def_id, lsb0, f);
|
||||
(*self.sty).iter_bytes(lsb0, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +231,7 @@ pub type ctxt = @ctxt_;
|
|||
|
||||
struct ctxt_ {
|
||||
diag: @syntax::diagnostic::span_handler,
|
||||
interner: @mut HashMap<intern_key, t_box>,
|
||||
interner: @mut HashMap<intern_key, ~t_box_>,
|
||||
next_id: @mut uint,
|
||||
vecs_implicitly_copyable: bool,
|
||||
legacy_modes: bool,
|
||||
|
@ -307,7 +306,7 @@ struct ctxt_ {
|
|||
used_unsafe: @mut HashSet<ast::node_id>,
|
||||
}
|
||||
|
||||
enum tbox_flag {
|
||||
pub enum tbox_flag {
|
||||
has_params = 1,
|
||||
has_self = 2,
|
||||
needs_infer = 4,
|
||||
|
@ -320,13 +319,12 @@ enum tbox_flag {
|
|||
needs_subst = 1 | 2 | 8
|
||||
}
|
||||
|
||||
type t_box = @t_box_;
|
||||
pub type t_box = &'static t_box_;
|
||||
|
||||
struct t_box_ {
|
||||
pub struct t_box_ {
|
||||
sty: sty,
|
||||
id: uint,
|
||||
flags: uint,
|
||||
o_def_id: Option<ast::def_id>
|
||||
}
|
||||
|
||||
// To reduce refcounting cost, we're representing types as unsafe pointers
|
||||
|
@ -359,7 +357,6 @@ pub fn type_needs_infer(t: t) -> bool {
|
|||
pub fn type_has_regions(t: t) -> bool {
|
||||
tbox_has_flag(get(t), has_regions)
|
||||
}
|
||||
pub fn type_def_id(t: t) -> Option<ast::def_id> { get(t).o_def_id }
|
||||
pub fn type_id(t: t) -> uint { get(t).id }
|
||||
|
||||
#[deriving(Eq)]
|
||||
|
@ -513,6 +510,53 @@ pub struct substs {
|
|||
tps: ~[t]
|
||||
}
|
||||
|
||||
mod primitives {
|
||||
use super::{sty, t_box_};
|
||||
|
||||
use syntax::ast;
|
||||
|
||||
macro_rules! def_prim_ty(
|
||||
($name:ident, $sty:expr, $id:expr) => (
|
||||
pub static $name: t_box_ = t_box_ {
|
||||
sty: $sty,
|
||||
id: $id,
|
||||
flags: 0,
|
||||
};
|
||||
)
|
||||
)
|
||||
|
||||
def_prim_ty!(TY_NIL, super::ty_nil, 0)
|
||||
def_prim_ty!(TY_BOOL, super::ty_bool, 1)
|
||||
def_prim_ty!(TY_INT, super::ty_int(ast::ty_i), 2)
|
||||
def_prim_ty!(TY_CHAR, super::ty_int(ast::ty_char), 3)
|
||||
def_prim_ty!(TY_I8, super::ty_int(ast::ty_i8), 4)
|
||||
def_prim_ty!(TY_I16, super::ty_int(ast::ty_i16), 5)
|
||||
def_prim_ty!(TY_I32, super::ty_int(ast::ty_i32), 6)
|
||||
def_prim_ty!(TY_I64, super::ty_int(ast::ty_i64), 7)
|
||||
def_prim_ty!(TY_UINT, super::ty_uint(ast::ty_u), 8)
|
||||
def_prim_ty!(TY_U8, super::ty_uint(ast::ty_u8), 9)
|
||||
def_prim_ty!(TY_U16, super::ty_uint(ast::ty_u16), 10)
|
||||
def_prim_ty!(TY_U32, super::ty_uint(ast::ty_u32), 11)
|
||||
def_prim_ty!(TY_U64, super::ty_uint(ast::ty_u64), 12)
|
||||
def_prim_ty!(TY_FLOAT, super::ty_float(ast::ty_f), 13)
|
||||
def_prim_ty!(TY_F32, super::ty_float(ast::ty_f32), 14)
|
||||
def_prim_ty!(TY_F64, super::ty_float(ast::ty_f64), 15)
|
||||
|
||||
pub static TY_BOT: t_box_ = t_box_ {
|
||||
sty: super::ty_bot,
|
||||
id: 16,
|
||||
flags: super::has_ty_bot as uint,
|
||||
};
|
||||
|
||||
pub static TY_ERR: t_box_ = t_box_ {
|
||||
sty: super::ty_err,
|
||||
id: 17,
|
||||
flags: super::has_ty_err as uint,
|
||||
};
|
||||
|
||||
pub static LAST_PRIMITIVE_ID: uint = 18;
|
||||
}
|
||||
|
||||
// NB: If you change this, you'll probably want to change the corresponding
|
||||
// AST structure in libsyntax/ast.rs as well.
|
||||
#[deriving(Eq)]
|
||||
|
@ -852,7 +896,7 @@ pub fn mk_ctxt(s: session::Session,
|
|||
@ctxt_ {
|
||||
diag: s.diagnostic(),
|
||||
interner: @mut HashMap::new(),
|
||||
next_id: @mut 0,
|
||||
next_id: @mut primitives::LAST_PRIMITIVE_ID,
|
||||
vecs_implicitly_copyable: vecs_implicitly_copyable,
|
||||
legacy_modes: legacy_modes,
|
||||
cstore: s.cstore,
|
||||
|
@ -894,16 +938,25 @@ pub fn mk_ctxt(s: session::Session,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Type constructors
|
||||
fn mk_t(cx: ctxt, +st: sty) -> t { mk_t_with_id(cx, st, None) }
|
||||
|
||||
// Interns a type/name combination, stores the resulting box in cx.interner,
|
||||
// and returns the box as cast to an unsafe ptr (see comments for t above).
|
||||
fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option<ast::def_id>) -> t {
|
||||
let key = intern_key { sty: to_unsafe_ptr(&st), o_def_id: o_def_id };
|
||||
fn mk_t(cx: ctxt, +st: sty) -> t {
|
||||
// Check for primitive types.
|
||||
match st {
|
||||
ty_nil => return mk_nil(cx),
|
||||
ty_err => return mk_err(cx),
|
||||
ty_bool => return mk_bool(cx),
|
||||
ty_int(i) => return mk_mach_int(cx, i),
|
||||
ty_uint(u) => return mk_mach_uint(cx, u),
|
||||
ty_float(f) => return mk_mach_float(cx, f),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let key = intern_key { sty: to_unsafe_ptr(&st) };
|
||||
match cx.interner.find(&key) {
|
||||
Some(&t) => unsafe { return cast::reinterpret_cast(&t); },
|
||||
Some(t) => unsafe { return cast::transmute(&t.sty); },
|
||||
_ => ()
|
||||
}
|
||||
|
||||
|
@ -973,66 +1026,116 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option<ast::def_id>) -> t {
|
|||
}
|
||||
}
|
||||
|
||||
let t = @t_box_ {
|
||||
let t = ~t_box_ {
|
||||
sty: st,
|
||||
id: *cx.next_id,
|
||||
flags: flags,
|
||||
o_def_id: o_def_id
|
||||
};
|
||||
|
||||
let sty_ptr = to_unsafe_ptr(&t.sty);
|
||||
|
||||
let key = intern_key {
|
||||
sty: to_unsafe_ptr(&t.sty),
|
||||
o_def_id: o_def_id
|
||||
sty: sty_ptr,
|
||||
};
|
||||
|
||||
cx.interner.insert(key, t);
|
||||
|
||||
*cx.next_id += 1;
|
||||
unsafe { cast::reinterpret_cast(&t) }
|
||||
|
||||
unsafe {
|
||||
cast::transmute::<*sty, t>(sty_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_nil(cx: ctxt) -> t { mk_t(cx, ty_nil) }
|
||||
#[inline(always)]
|
||||
pub fn mk_prim_t(cx: ctxt, primitive: &'static t_box_) -> t {
|
||||
unsafe {
|
||||
cast::transmute::<&'static t_box_, t>(primitive)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_err(cx: ctxt) -> t { mk_t(cx, ty_err) }
|
||||
#[inline(always)]
|
||||
pub fn mk_nil(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_NIL) }
|
||||
|
||||
pub fn mk_bot(cx: ctxt) -> t { mk_t(cx, ty_bot) }
|
||||
#[inline(always)]
|
||||
pub fn mk_err(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_ERR) }
|
||||
|
||||
pub fn mk_bool(cx: ctxt) -> t { mk_t(cx, ty_bool) }
|
||||
#[inline(always)]
|
||||
pub fn mk_bot(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_BOT) }
|
||||
|
||||
pub fn mk_int(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_bool(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_BOOL) }
|
||||
|
||||
pub fn mk_i8(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i8)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_int(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_INT) }
|
||||
|
||||
pub fn mk_i16(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i16)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_i8(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_I8) }
|
||||
|
||||
pub fn mk_i32(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i32)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_i16(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_I16) }
|
||||
|
||||
pub fn mk_i64(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_i64)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_i32(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_I32) }
|
||||
|
||||
pub fn mk_float(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_i64(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_I64) }
|
||||
|
||||
pub fn mk_uint(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_float(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_FLOAT) }
|
||||
|
||||
pub fn mk_u8(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u8)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_f32(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_F32) }
|
||||
|
||||
pub fn mk_u16(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u16)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_f64(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_F64) }
|
||||
|
||||
pub fn mk_u32(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u32)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_uint(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_UINT) }
|
||||
|
||||
pub fn mk_u64(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u64)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_u8(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_U8) }
|
||||
|
||||
pub fn mk_f32(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f32)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_u16(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_U16) }
|
||||
|
||||
pub fn mk_f64(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f64)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_u32(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_U32) }
|
||||
|
||||
pub fn mk_mach_int(cx: ctxt, tm: ast::int_ty) -> t { mk_t(cx, ty_int(tm)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_u64(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_U64) }
|
||||
|
||||
pub fn mk_mach_uint(cx: ctxt, tm: ast::uint_ty) -> t { mk_t(cx, ty_uint(tm)) }
|
||||
pub fn mk_mach_int(cx: ctxt, tm: ast::int_ty) -> t {
|
||||
match tm {
|
||||
ast::ty_i => mk_int(cx),
|
||||
ast::ty_char => mk_char(cx),
|
||||
ast::ty_i8 => mk_i8(cx),
|
||||
ast::ty_i16 => mk_i16(cx),
|
||||
ast::ty_i32 => mk_i32(cx),
|
||||
ast::ty_i64 => mk_i64(cx),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_mach_uint(cx: ctxt, tm: ast::uint_ty) -> t {
|
||||
match tm {
|
||||
ast::ty_u => mk_uint(cx),
|
||||
ast::ty_u8 => mk_u8(cx),
|
||||
ast::ty_u16 => mk_u16(cx),
|
||||
ast::ty_u32 => mk_u32(cx),
|
||||
ast::ty_u64 => mk_u64(cx),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_mach_float(cx: ctxt, tm: ast::float_ty) -> t {
|
||||
mk_t(cx, ty_float(tm))
|
||||
match tm {
|
||||
ast::ty_f => mk_float(cx),
|
||||
ast::ty_f32 => mk_f32(cx),
|
||||
ast::ty_f64 => mk_f64(cx),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_char(cx: ctxt) -> t { mk_t(cx, ty_int(ast::ty_char)) }
|
||||
#[inline(always)]
|
||||
pub fn mk_char(cx: ctxt) -> t { mk_prim_t(cx, &primitives::TY_CHAR) }
|
||||
|
||||
pub fn mk_estr(cx: ctxt, t: vstore) -> t {
|
||||
mk_t(cx, ty_estr(t))
|
||||
|
@ -1149,10 +1252,6 @@ pub fn mk_opaque_closure_ptr(cx: ctxt, sigil: ast::Sigil) -> t {
|
|||
|
||||
pub fn mk_opaque_box(cx: ctxt) -> t { mk_t(cx, ty_opaque_box) }
|
||||
|
||||
pub fn mk_with_id(cx: ctxt, base: t, def_id: ast::def_id) -> t {
|
||||
mk_t_with_id(cx, /*bad*/copy get(base).sty, Some(def_id))
|
||||
}
|
||||
|
||||
// Converts s to its machine type equivalent
|
||||
pub fn mach_sty(cfg: @session::config, t: t) -> sty {
|
||||
match get(t).sty {
|
||||
|
|
|
@ -1085,16 +1085,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item)
|
|||
let region_parameterization =
|
||||
RegionParameterization::from_variance_and_generics(rp, generics);
|
||||
let tpt = {
|
||||
let ty = {
|
||||
let t0 = ccx.to_ty(&type_rscope(region_parameterization), t);
|
||||
// Do not associate a def id with a named, parameterized type
|
||||
// like "foo<X>". This is because otherwise ty_to_str will
|
||||
// print the name as merely "foo", as it has no way to
|
||||
// reconstruct the value of X.
|
||||
if generics.is_parameterized() { t0 } else {
|
||||
ty::mk_with_id(tcx, t0, def_id)
|
||||
}
|
||||
};
|
||||
let ty = ccx.to_ty(&type_rscope(region_parameterization), t);
|
||||
ty_param_bounds_and_ty {
|
||||
generics: ty_generics(ccx, rp, generics, 0),
|
||||
ty: ty
|
||||
|
|
|
@ -59,10 +59,13 @@ pub mod reader {
|
|||
use ebml::{EsVec, EsVecElt, EsVecLen, TaggedDoc};
|
||||
use serialize;
|
||||
|
||||
use core::cast::transmute;
|
||||
use core::int;
|
||||
use core::io;
|
||||
use core::prelude::*;
|
||||
use core::ptr::offset;
|
||||
use core::str;
|
||||
use core::unstable::intrinsics::bswap32;
|
||||
use core::vec;
|
||||
|
||||
// ebml reading
|
||||
|
@ -78,7 +81,8 @@ pub mod reader {
|
|||
next: uint
|
||||
}
|
||||
|
||||
fn vuint_at(data: &[u8], start: uint) -> Res {
|
||||
#[inline(never)]
|
||||
fn vuint_at_slow(data: &[u8], start: uint) -> Res {
|
||||
let a = data[start];
|
||||
if a & 0x80u8 != 0u8 {
|
||||
return Res {val: (a & 0x7fu8) as uint, next: start + 1u};
|
||||
|
@ -87,18 +91,63 @@ pub mod reader {
|
|||
return Res {val: ((a & 0x3fu8) as uint) << 8u |
|
||||
(data[start + 1u] as uint),
|
||||
next: start + 2u};
|
||||
} else if a & 0x20u8 != 0u8 {
|
||||
}
|
||||
if a & 0x20u8 != 0u8 {
|
||||
return Res {val: ((a & 0x1fu8) as uint) << 16u |
|
||||
(data[start + 1u] as uint) << 8u |
|
||||
(data[start + 2u] as uint),
|
||||
next: start + 3u};
|
||||
} else if a & 0x10u8 != 0u8 {
|
||||
}
|
||||
if a & 0x10u8 != 0u8 {
|
||||
return Res {val: ((a & 0x0fu8) as uint) << 24u |
|
||||
(data[start + 1u] as uint) << 16u |
|
||||
(data[start + 2u] as uint) << 8u |
|
||||
(data[start + 3u] as uint),
|
||||
next: start + 4u};
|
||||
} else { error!("vint too big"); fail!(); }
|
||||
}
|
||||
fail!(~"vint too big");
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn vuint_at(data: &[u8], start: uint) -> Res {
|
||||
if data.len() - start < 4 {
|
||||
return vuint_at_slow(data, start);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let (ptr, _): (*u8, uint) = transmute(data);
|
||||
let ptr = offset(ptr, start);
|
||||
let ptr: *i32 = transmute(ptr);
|
||||
let val = bswap32(*ptr);
|
||||
let val: u32 = transmute(val);
|
||||
if (val & 0x80000000) != 0 {
|
||||
Res {
|
||||
val: ((val >> 24) & 0x7f) as uint,
|
||||
next: start + 1
|
||||
}
|
||||
} else if (val & 0x40000000) != 0 {
|
||||
Res {
|
||||
val: ((val >> 16) & 0x3fff) as uint,
|
||||
next: start + 2
|
||||
}
|
||||
} else if (val & 0x20000000) != 0 {
|
||||
Res {
|
||||
val: ((val >> 8) & 0x1fffff) as uint,
|
||||
next: start + 3
|
||||
}
|
||||
} else {
|
||||
Res {
|
||||
val: (val & 0x0fffffff) as uint,
|
||||
next: start + 4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
pub fn vuint_at(data: &[u8], start: uint) -> Res {
|
||||
vuint_at_slow(data, start)
|
||||
}
|
||||
|
||||
pub fn Doc(data: @~[u8]) -> Doc {
|
||||
|
|
|
@ -222,7 +222,11 @@ pub fn connect(input_ip: ip::IpAddr, port: uint,
|
|||
};
|
||||
match connect_result {
|
||||
0i32 => {
|
||||
debug!("tcp_connect successful");
|
||||
debug!("tcp_connect successful: \
|
||||
stream %x,
|
||||
socket data %x",
|
||||
stream_handle_ptr as uint,
|
||||
socket_data_ptr as uint);
|
||||
// reusable data that we'll have for the
|
||||
// duration..
|
||||
uv::ll::set_data_for_uv_handle(
|
||||
|
@ -556,13 +560,21 @@ pub fn accept(new_conn: TcpNewConnection)
|
|||
server_handle_ptr as *libc::c_void,
|
||||
client_stream_handle_ptr as *libc::c_void) {
|
||||
0i32 => {
|
||||
debug!(
|
||||
"successfully accepted client \
|
||||
connection");
|
||||
debug!("successfully accepted client \
|
||||
connection: \
|
||||
stream %x, \
|
||||
socket data %x",
|
||||
client_stream_handle_ptr as uint,
|
||||
client_socket_data_ptr as uint);
|
||||
uv::ll::set_data_for_uv_handle(
|
||||
client_stream_handle_ptr,
|
||||
client_socket_data_ptr
|
||||
as *libc::c_void);
|
||||
let ptr = uv::ll::get_data_for_uv_handle(
|
||||
client_stream_handle_ptr);
|
||||
debug!("ptrs: %x %x",
|
||||
client_socket_data_ptr as uint,
|
||||
ptr as uint);
|
||||
result_ch.send(None);
|
||||
}
|
||||
_ => {
|
||||
|
@ -1268,14 +1280,15 @@ impl ToTcpErr for uv::ll::uv_err_data {
|
|||
}
|
||||
|
||||
extern fn on_tcp_read_cb(stream: *uv::ll::uv_stream_t,
|
||||
nread: libc::ssize_t,
|
||||
buf: uv::ll::uv_buf_t) {
|
||||
nread: libc::ssize_t,
|
||||
buf: uv::ll::uv_buf_t) {
|
||||
unsafe {
|
||||
debug!("entering on_tcp_read_cb stream: %? nread: %?",
|
||||
stream, nread);
|
||||
debug!("entering on_tcp_read_cb stream: %x nread: %?",
|
||||
stream as uint, nread);
|
||||
let loop_ptr = uv::ll::get_loop_for_uv_handle(stream);
|
||||
let socket_data_ptr = uv::ll::get_data_for_uv_handle(stream)
|
||||
as *TcpSocketData;
|
||||
debug!("socket data is %x", socket_data_ptr as uint);
|
||||
match nread as int {
|
||||
// incoming err.. probably eof
|
||||
-1 => {
|
||||
|
|
|
@ -1156,8 +1156,7 @@ pub unsafe fn set_data_for_uv_loop(loop_ptr: *libc::c_void,
|
|||
pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *libc::c_void {
|
||||
return rustrt::rust_uv_get_data_for_uv_handle(handle as *libc::c_void);
|
||||
}
|
||||
pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T,
|
||||
data: *U) {
|
||||
pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
|
||||
rustrt::rust_uv_set_data_for_uv_handle(handle as *libc::c_void,
|
||||
data as *libc::c_void);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@ use util::interner;
|
|||
|
||||
use core::cast;
|
||||
use core::char;
|
||||
use core::cmp::Equiv;
|
||||
use core::hashmap::HashSet;
|
||||
use core::str;
|
||||
use core::task;
|
||||
use core::to_bytes;
|
||||
|
||||
#[auto_encode]
|
||||
#[auto_decode]
|
||||
|
@ -355,16 +357,29 @@ pub mod special_idents {
|
|||
pub static type_self: ident = ident { repr: 36u, ctxt: 0}; // `Self`
|
||||
}
|
||||
|
||||
pub struct StringRef<'self>(&'self str);
|
||||
|
||||
impl<'self> Equiv<@~str> for StringRef<'self> {
|
||||
#[inline(always)]
|
||||
fn equiv(&self, other: &@~str) -> bool { str::eq_slice(**self, **other) }
|
||||
}
|
||||
|
||||
impl<'self> to_bytes::IterBytes for StringRef<'self> {
|
||||
fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
|
||||
(**self).iter_bytes(lsb0, f);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ident_interner {
|
||||
priv interner: Interner<@~str>,
|
||||
}
|
||||
|
||||
pub impl ident_interner {
|
||||
fn intern(&self, val: @~str) -> ast::ident {
|
||||
ast::ident { repr: self.interner.intern(val), ctxt: 0}
|
||||
ast::ident { repr: self.interner.intern(val), ctxt: 0 }
|
||||
}
|
||||
fn gensym(&self, val: @~str) -> ast::ident {
|
||||
ast::ident { repr: self.interner.gensym(val), ctxt: 0}
|
||||
ast::ident { repr: self.interner.gensym(val), ctxt: 0 }
|
||||
}
|
||||
fn get(&self, idx: ast::ident) -> @~str {
|
||||
self.interner.get(idx.repr)
|
||||
|
@ -372,6 +387,13 @@ pub impl ident_interner {
|
|||
fn len(&self) -> uint {
|
||||
self.interner.len()
|
||||
}
|
||||
fn find_equiv<Q:Hash + IterBytes + Equiv<@~str>>(&self, val: &Q)
|
||||
-> Option<ast::ident> {
|
||||
match self.interner.find_equiv(val) {
|
||||
Some(v) => Some(ast::ident { repr: v, ctxt: 0 }),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mk_ident_interner() -> @ident_interner {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#[macro_escape];
|
||||
|
||||
use core::prelude::*;
|
||||
use core::cmp::Equiv;
|
||||
use core::hashmap::HashMap;
|
||||
|
||||
pub struct Interner<T> {
|
||||
|
@ -67,6 +68,14 @@ pub impl<T:Eq + IterBytes + Hash + Const + Copy> Interner<T> {
|
|||
fn get(&self, idx: uint) -> T { self.vect[idx] }
|
||||
|
||||
fn len(&self) -> uint { let vect = &*self.vect; vect.len() }
|
||||
|
||||
fn find_equiv<Q:Hash + IterBytes + Equiv<T>>(&self, val: &Q)
|
||||
-> Option<uint> {
|
||||
match self.map.find_equiv(val) {
|
||||
Some(v) => Some(*v),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Key for thread-local data for sneaking interner information to the
|
||||
|
|
|
@ -29,6 +29,8 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, int id, bool killed) :
|
|||
should_exit(false),
|
||||
cached_c_stack(NULL),
|
||||
extra_c_stack(NULL),
|
||||
cached_big_stack(NULL),
|
||||
extra_big_stack(NULL),
|
||||
dead_task(NULL),
|
||||
killed(killed),
|
||||
pump_signal(NULL),
|
||||
|
@ -263,6 +265,11 @@ rust_sched_loop::run_single_turn() {
|
|||
destroy_exchange_stack(kernel->region(), cached_c_stack);
|
||||
cached_c_stack = NULL;
|
||||
}
|
||||
assert(!extra_big_stack);
|
||||
if (cached_big_stack) {
|
||||
destroy_exchange_stack(kernel->region(), cached_big_stack);
|
||||
cached_big_stack = NULL;
|
||||
}
|
||||
|
||||
sched->release_task_thread();
|
||||
return sched_loop_state_exit;
|
||||
|
@ -392,6 +399,13 @@ rust_sched_loop::prepare_c_stack(rust_task *task) {
|
|||
cached_c_stack = create_exchange_stack(kernel->region(),
|
||||
C_STACK_SIZE);
|
||||
}
|
||||
assert(!extra_big_stack);
|
||||
if (!cached_big_stack) {
|
||||
cached_big_stack = create_exchange_stack(kernel->region(),
|
||||
C_STACK_SIZE +
|
||||
(C_STACK_SIZE * 2));
|
||||
cached_big_stack->is_big = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -400,6 +414,10 @@ rust_sched_loop::unprepare_c_stack() {
|
|||
destroy_exchange_stack(kernel->region(), extra_c_stack);
|
||||
extra_c_stack = NULL;
|
||||
}
|
||||
if (extra_big_stack) {
|
||||
destroy_exchange_stack(kernel->region(), extra_big_stack);
|
||||
extra_big_stack = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -67,6 +67,8 @@ private:
|
|||
|
||||
stk_seg *cached_c_stack;
|
||||
stk_seg *extra_c_stack;
|
||||
stk_seg *cached_big_stack;
|
||||
stk_seg *extra_big_stack;
|
||||
|
||||
rust_task_list running_tasks;
|
||||
rust_task_list blocked_tasks;
|
||||
|
@ -147,6 +149,10 @@ public:
|
|||
stk_seg *borrow_c_stack();
|
||||
void return_c_stack(stk_seg *stack);
|
||||
|
||||
// Called by tasks when they need a big stack
|
||||
stk_seg *borrow_big_stack();
|
||||
void return_big_stack(stk_seg *stack);
|
||||
|
||||
int get_id() { return this->id; }
|
||||
};
|
||||
|
||||
|
@ -202,6 +208,32 @@ rust_sched_loop::return_c_stack(stk_seg *stack) {
|
|||
}
|
||||
}
|
||||
|
||||
// NB: Runs on the Rust stack. Might return NULL!
|
||||
inline stk_seg *
|
||||
rust_sched_loop::borrow_big_stack() {
|
||||
assert(cached_big_stack);
|
||||
stk_seg *your_stack;
|
||||
if (extra_big_stack) {
|
||||
your_stack = extra_big_stack;
|
||||
extra_big_stack = NULL;
|
||||
} else {
|
||||
your_stack = cached_big_stack;
|
||||
cached_big_stack = NULL;
|
||||
}
|
||||
return your_stack;
|
||||
}
|
||||
|
||||
// NB: Runs on the Rust stack
|
||||
inline void
|
||||
rust_sched_loop::return_big_stack(stk_seg *stack) {
|
||||
assert(!extra_big_stack);
|
||||
assert(stack);
|
||||
if (!cached_big_stack)
|
||||
cached_big_stack = stack;
|
||||
else
|
||||
extra_big_stack = stack;
|
||||
}
|
||||
|
||||
// this is needed to appease the circular dependency gods
|
||||
#include "rust_task.h"
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "vg/valgrind.h"
|
||||
#include "vg/memcheck.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef _LP64
|
||||
const uintptr_t canary_value = 0xABCDABCDABCDABCD;
|
||||
#else
|
||||
|
@ -61,6 +63,7 @@ create_stack(memory_region *region, size_t sz) {
|
|||
stk_seg *stk = (stk_seg *)region->malloc(total_sz, "stack");
|
||||
memset(stk, 0, sizeof(stk_seg));
|
||||
stk->end = (uintptr_t) &stk->data[sz];
|
||||
stk->is_big = 0;
|
||||
add_stack_canary(stk);
|
||||
register_valgrind_stack(stk);
|
||||
return stk;
|
||||
|
@ -78,6 +81,7 @@ create_exchange_stack(rust_exchange_alloc *exchange, size_t sz) {
|
|||
stk_seg *stk = (stk_seg *)exchange->malloc(total_sz);
|
||||
memset(stk, 0, sizeof(stk_seg));
|
||||
stk->end = (uintptr_t) &stk->data[sz];
|
||||
stk->is_big = 0;
|
||||
add_stack_canary(stk);
|
||||
register_valgrind_stack(stk);
|
||||
return stk;
|
||||
|
|
|
@ -22,9 +22,7 @@ struct stk_seg {
|
|||
stk_seg *next;
|
||||
uintptr_t end;
|
||||
unsigned int valgrind_id;
|
||||
#ifndef _LP64
|
||||
uint32_t pad;
|
||||
#endif
|
||||
uint8_t is_big;
|
||||
|
||||
rust_task *task;
|
||||
uintptr_t canary;
|
||||
|
|
|
@ -53,7 +53,8 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state,
|
|||
disallow_yield(0),
|
||||
c_stack(NULL),
|
||||
next_c_sp(0),
|
||||
next_rust_sp(0)
|
||||
next_rust_sp(0),
|
||||
big_stack(NULL)
|
||||
{
|
||||
LOGPTR(sched_loop, "new task", (uintptr_t)this);
|
||||
DLOG(sched_loop, task, "sizeof(task) = %d (0x%x)",
|
||||
|
@ -457,8 +458,9 @@ rust_task::get_next_stack_size(size_t min, size_t current, size_t requested) {
|
|||
"min: %" PRIdPTR " current: %" PRIdPTR " requested: %" PRIdPTR,
|
||||
min, current, requested);
|
||||
|
||||
// Allocate at least enough to accomodate the next frame
|
||||
size_t sz = std::max(min, requested);
|
||||
// Allocate at least enough to accomodate the next frame, plus a little
|
||||
// slack to avoid thrashing
|
||||
size_t sz = std::max(min, requested + (requested / 2));
|
||||
|
||||
// And double the stack size each allocation
|
||||
const size_t max = 1024 * 1024;
|
||||
|
@ -555,13 +557,63 @@ rust_task::cleanup_after_turn() {
|
|||
// Delete any spare stack segments that were left
|
||||
// behind by calls to prev_stack
|
||||
assert(stk);
|
||||
|
||||
while (stk->next) {
|
||||
stk_seg *new_next = stk->next->next;
|
||||
free_stack(stk->next);
|
||||
|
||||
if (stk->next->is_big) {
|
||||
assert (big_stack == stk->next);
|
||||
sched_loop->return_big_stack(big_stack);
|
||||
big_stack = NULL;
|
||||
} else {
|
||||
free_stack(stk->next);
|
||||
}
|
||||
|
||||
stk->next = new_next;
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Runs on the Rust stack. Returns true if we successfully allocated the big
|
||||
// stack and false otherwise.
|
||||
bool
|
||||
rust_task::new_big_stack() {
|
||||
// If we have a cached big stack segment, use it.
|
||||
if (big_stack) {
|
||||
// Check to see if we're already on the big stack.
|
||||
stk_seg *ss = stk;
|
||||
while (ss != NULL) {
|
||||
if (ss == big_stack)
|
||||
return false;
|
||||
ss = ss->prev;
|
||||
}
|
||||
|
||||
// Unlink the big stack.
|
||||
if (big_stack->next)
|
||||
big_stack->next->prev = big_stack->prev;
|
||||
if (big_stack->prev)
|
||||
big_stack->prev->next = big_stack->next;
|
||||
} else {
|
||||
stk_seg *borrowed_big_stack = sched_loop->borrow_big_stack();
|
||||
if (!borrowed_big_stack) {
|
||||
abort();
|
||||
} else {
|
||||
big_stack = borrowed_big_stack;
|
||||
}
|
||||
}
|
||||
|
||||
big_stack->task = this;
|
||||
big_stack->next = stk->next;
|
||||
if (big_stack->next)
|
||||
big_stack->next->prev = big_stack;
|
||||
big_stack->prev = stk;
|
||||
if (stk)
|
||||
stk->next = big_stack;
|
||||
|
||||
stk = big_stack;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
sp_in_stk_seg(uintptr_t sp, stk_seg *stk) {
|
||||
// Not positive these bounds for sp are correct. I think that the first
|
||||
|
@ -601,9 +653,16 @@ rust_task::delete_all_stacks() {
|
|||
assert(stk->next == NULL);
|
||||
while (stk != NULL) {
|
||||
stk_seg *prev = stk->prev;
|
||||
free_stack(stk);
|
||||
|
||||
if (stk->is_big)
|
||||
sched_loop->return_big_stack(stk);
|
||||
else
|
||||
free_stack(stk);
|
||||
|
||||
stk = prev;
|
||||
}
|
||||
|
||||
big_stack = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -133,6 +133,9 @@
|
|||
#define RZ_BSD_32 (1024*20)
|
||||
#define RZ_BSD_64 (1024*20)
|
||||
|
||||
// The threshold beyond which we switch to the C stack.
|
||||
#define STACK_THRESHOLD (1024 * 1024)
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef __i386__
|
||||
#define RED_ZONE_SIZE RZ_LINUX_32
|
||||
|
@ -263,9 +266,13 @@ private:
|
|||
uintptr_t next_c_sp;
|
||||
uintptr_t next_rust_sp;
|
||||
|
||||
// The big stack.
|
||||
stk_seg *big_stack;
|
||||
|
||||
// Called when the atomic refcount reaches zero
|
||||
void delete_this();
|
||||
|
||||
bool new_big_stack();
|
||||
void new_stack_fast(size_t requested_sz);
|
||||
void new_stack(size_t requested_sz);
|
||||
void free_stack(stk_seg *stk);
|
||||
|
@ -568,6 +575,11 @@ rust_task::new_stack_fast(size_t requested_sz) {
|
|||
// The minimum stack size, in bytes, of a Rust stack, excluding red zone
|
||||
size_t min_sz = sched_loop->min_stack_size;
|
||||
|
||||
if (requested_sz > STACK_THRESHOLD) {
|
||||
if (new_big_stack())
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to reuse an existing stack segment
|
||||
if (stk != NULL && stk->next != NULL) {
|
||||
size_t next_sz = user_stack_size(stk->next);
|
||||
|
|
|
@ -191,6 +191,14 @@ rust_upcall_malloc(type_desc *td, uintptr_t size) {
|
|||
return upcall_malloc(td, size);
|
||||
}
|
||||
|
||||
extern "C" CDECL uintptr_t
|
||||
rust_upcall_malloc_noswitch(type_desc *td, uintptr_t size) {
|
||||
rust_task *task = rust_get_current_task();
|
||||
s_malloc_args args = {task, 0, td, size};
|
||||
upcall_s_malloc(&args);
|
||||
return args.retval;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Called whenever an object in the task-local heap is freed.
|
||||
*/
|
||||
|
@ -231,6 +239,13 @@ rust_upcall_free(void* ptr) {
|
|||
upcall_free(ptr);
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
rust_upcall_free_noswitch(void* ptr) {
|
||||
rust_task *task = rust_get_current_task();
|
||||
s_free_args args = {task,ptr};
|
||||
upcall_s_free(&args);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
extern "C" _Unwind_Reason_Code
|
||||
|
|
|
@ -401,8 +401,7 @@ rust_uv_get_data_for_uv_handle(uv_handle_t* handle) {
|
|||
}
|
||||
|
||||
extern "C" void
|
||||
rust_uv_set_data_for_uv_handle(uv_handle_t* handle,
|
||||
void* data) {
|
||||
rust_uv_set_data_for_uv_handle(uv_handle_t* handle, void* data) {
|
||||
handle->data = data;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,9 @@ upcall_del_stack
|
|||
upcall_reset_stack_limit
|
||||
rust_upcall_fail
|
||||
rust_upcall_free
|
||||
rust_upcall_free_noswitch
|
||||
rust_upcall_malloc
|
||||
rust_upcall_malloc_noswitch
|
||||
rust_uv_loop_new
|
||||
rust_uv_loop_delete
|
||||
rust_uv_walk
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===
|
||||
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/Linker.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
|
@ -152,7 +154,9 @@ public:
|
|||
unsigned SectionID);
|
||||
|
||||
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID);
|
||||
unsigned SectionID, bool isReadOnly);
|
||||
|
||||
virtual bool applyPermissions(std::string *Str);
|
||||
|
||||
virtual void *getPointerToNamedFunction(const std::string &Name,
|
||||
bool AbortOnFailure = true);
|
||||
|
@ -218,12 +222,6 @@ public:
|
|||
virtual void deallocateExceptionTable(void *ET) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
virtual uint8_t* allocateDataSection(uintptr_t, unsigned int, unsigned int, bool) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
virtual bool applyPermissions(std::string*) {
|
||||
llvm_unreachable("Unimplemented call");
|
||||
}
|
||||
};
|
||||
|
||||
bool RustMCJITMemoryManager::loadCrate(const char* file, std::string* err) {
|
||||
|
@ -240,8 +238,9 @@ bool RustMCJITMemoryManager::loadCrate(const char* file, std::string* err) {
|
|||
}
|
||||
|
||||
uint8_t *RustMCJITMemoryManager::allocateDataSection(uintptr_t Size,
|
||||
unsigned Alignment,
|
||||
unsigned SectionID) {
|
||||
unsigned Alignment,
|
||||
unsigned SectionID,
|
||||
bool isReadOnly) {
|
||||
if (!Alignment)
|
||||
Alignment = 16;
|
||||
uint8_t *Addr = (uint8_t*)calloc((Size + Alignment - 1)/Alignment, Alignment);
|
||||
|
@ -249,9 +248,14 @@ uint8_t *RustMCJITMemoryManager::allocateDataSection(uintptr_t Size,
|
|||
return Addr;
|
||||
}
|
||||
|
||||
bool RustMCJITMemoryManager::applyPermissions(std::string *Str) {
|
||||
// Empty.
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *RustMCJITMemoryManager::allocateCodeSection(uintptr_t Size,
|
||||
unsigned Alignment,
|
||||
unsigned SectionID) {
|
||||
unsigned Alignment,
|
||||
unsigned SectionID) {
|
||||
if (!Alignment)
|
||||
Alignment = 16;
|
||||
unsigned NeedAllocate = Alignment * ((Size + Alignment - 1)/Alignment + 1);
|
||||
|
@ -451,6 +455,7 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
|
|||
TargetOptions Options;
|
||||
Options.NoFramePointerElim = true;
|
||||
Options.EnableSegmentedStacks = EnableSegmentedStacks;
|
||||
Options.FixedStackSegmentSize = 2 * 1024 * 1024; // XXX: This is too big.
|
||||
|
||||
PassManager *PM = unwrap<PassManager>(PMR);
|
||||
|
||||
|
@ -484,13 +489,12 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR,
|
|||
}
|
||||
|
||||
extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(const char *Filename) {
|
||||
|
||||
SMDiagnostic d;
|
||||
Module *m = ParseAssemblyFile(Filename, d, getGlobalContext());
|
||||
if (m) {
|
||||
return wrap(m);
|
||||
} else {
|
||||
LLVMRustError = d.getMessage().data();
|
||||
LLVMRustError = d.getMessage().str().c_str();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ fn vector<M: Map<uint, uint>>(map: &mut M, n_keys: uint, dist: &[uint]) {
|
|||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
let n_keys = {
|
||||
|
|
95
src/test/bench/shootout-fannkuch-redux.rs
Normal file
95
src/test/bench/shootout-fannkuch-redux.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
use core::from_str::FromStr;
|
||||
use core::i32::range;
|
||||
use core::vec::MutableVector;
|
||||
|
||||
fn max(a: i32, b: i32) -> i32 {
|
||||
if a > b {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn fannkuch_redux(n: i32) -> i32 {
|
||||
let mut perm = vec::from_elem(n as uint, 0i32);
|
||||
let mut perm1 = vec::from_fn(n as uint, |i| i as i32);
|
||||
let mut count = vec::from_elem(n as uint, 0i32);
|
||||
let mut max_flips_count = 0i32, perm_count = 0i32, checksum = 0i32;
|
||||
|
||||
let mut r = n;
|
||||
loop {
|
||||
unsafe {
|
||||
while r != 1 {
|
||||
count.unsafe_set((r-1) as uint, r);
|
||||
r -= 1;
|
||||
}
|
||||
|
||||
// XXX: Need each2_mut.
|
||||
for vec::eachi_mut(perm) |i, perm_i| {
|
||||
*perm_i = perm1.unsafe_get(i);
|
||||
}
|
||||
|
||||
let mut flips_count: i32 = 0;
|
||||
let mut k: i32;
|
||||
loop {
|
||||
k = perm.unsafe_get(0);
|
||||
if k == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let k2 = (k+1) >> 1;
|
||||
for range(0, k2) |i| {
|
||||
let (perm_i, perm_k_i) = {
|
||||
(perm.unsafe_get(i as uint),
|
||||
perm.unsafe_get((k-i) as uint))
|
||||
};
|
||||
perm.unsafe_set(i as uint, perm_k_i);
|
||||
perm.unsafe_set((k-i) as uint, perm_i);
|
||||
}
|
||||
flips_count += 1;
|
||||
}
|
||||
|
||||
max_flips_count = max(max_flips_count, flips_count);
|
||||
checksum += if perm_count % 2 == 0 {
|
||||
flips_count
|
||||
} else {
|
||||
-flips_count
|
||||
};
|
||||
|
||||
// Use incremental change to generate another permutation.
|
||||
loop {
|
||||
if r == n {
|
||||
println(checksum.to_str());
|
||||
return max_flips_count;
|
||||
}
|
||||
|
||||
let perm0 = perm1[0];
|
||||
let mut i: i32 = 0;
|
||||
while i < r {
|
||||
let j = i + 1;
|
||||
let perm1_j = { perm1.unsafe_get(j as uint) };
|
||||
perm1.unsafe_set(i as uint, perm1_j);
|
||||
i = j;
|
||||
}
|
||||
perm1.unsafe_set(r as uint, perm0);
|
||||
|
||||
let count_r = { count.unsafe_get(r as uint) };
|
||||
count.unsafe_set(r as uint, count_r - 1);
|
||||
if count.unsafe_get(r as uint) > 0 {
|
||||
break;
|
||||
}
|
||||
r += 1;
|
||||
}
|
||||
|
||||
perm_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn main() {
|
||||
let n: i32 = FromStr::from_str(os::args()[1]).get();
|
||||
println(fmt!("Pfannkuchen(%d) = %d", n as int, fannkuch_redux(n) as int));
|
||||
}
|
||||
|
|
@ -1,81 +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.
|
||||
|
||||
// Based on Isaac Gouy's fannkuchredux.csharp
|
||||
extern mod std;
|
||||
|
||||
fn fannkuch(n: int) -> int {
|
||||
fn perm1init(i: uint) -> int { return i as int; }
|
||||
|
||||
let mut perm = vec::from_elem(n as uint, 0);
|
||||
let mut perm1 = vec::from_fn(n as uint, |i| perm1init(i));
|
||||
let mut count = vec::from_elem(n as uint, 0);
|
||||
let mut f = 0;
|
||||
let mut i = 0;
|
||||
let mut k = 0;
|
||||
let mut r = 0;
|
||||
let mut flips = 0;
|
||||
let mut nperm = 0;
|
||||
let mut checksum = 0;
|
||||
r = n;
|
||||
while r > 0 {
|
||||
i = 0;
|
||||
while r != 1 { count[r - 1] = r; r -= 1; }
|
||||
while i < n { perm[i] = perm1[i]; i += 1; }
|
||||
// Count flips and update max and checksum
|
||||
|
||||
f = 0;
|
||||
k = perm[0];
|
||||
while k != 0 {
|
||||
i = 0;
|
||||
while 2 * i < k {
|
||||
let t = perm[i];
|
||||
perm[i] = perm[k - i];
|
||||
perm[k - i] = t;
|
||||
i += 1;
|
||||
}
|
||||
k = perm[0];
|
||||
f += 1;
|
||||
}
|
||||
if f > flips { flips = f; }
|
||||
if nperm & 0x1 == 0 { checksum += f; } else { checksum -= f; }
|
||||
// Use incremental change to generate another permutation
|
||||
|
||||
let mut go = true;
|
||||
while go {
|
||||
if r == n {
|
||||
io::println(fmt!("%d", checksum));
|
||||
return flips;
|
||||
}
|
||||
let p0 = perm1[0];
|
||||
i = 0;
|
||||
while i < r { let j = i + 1; perm1[i] = perm1[j]; i = j; }
|
||||
perm1[r] = p0;
|
||||
count[r] -= 1;
|
||||
if count[r] > 0 { go = false; } else { r += 1; }
|
||||
}
|
||||
nperm += 1;
|
||||
}
|
||||
return flips;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
let args = if os::getenv(~"RUST_BENCH").is_some() {
|
||||
~[~"", ~"10"]
|
||||
} else if args.len() <= 1u {
|
||||
~[~"", ~"8"]
|
||||
} else {
|
||||
args
|
||||
};
|
||||
|
||||
let n = int::from_str(args[1]).get();
|
||||
io::println(fmt!("Pfannkuchen(%d) = %d", n, fannkuch(n)));
|
||||
}
|
204
src/test/bench/shootout-fasta-redux.rs
Normal file
204
src/test/bench/shootout-fasta-redux.rs
Normal file
|
@ -0,0 +1,204 @@
|
|||
use core::cast::transmute;
|
||||
use core::from_str::FromStr;
|
||||
use core::libc::{FILE, STDOUT_FILENO, c_int, fdopen, fputc, fputs, fwrite};
|
||||
use core::uint::{min, range};
|
||||
use core::vec::bytes::copy_memory;
|
||||
|
||||
static LINE_LEN: uint = 60;
|
||||
static LOOKUP_SIZE: uint = 4 * 1024;
|
||||
static LOOKUP_SCALE: f32 = (LOOKUP_SIZE - 1) as f32;
|
||||
|
||||
// Random number generator constants
|
||||
static IM: u32 = 139968;
|
||||
static IA: u32 = 3877;
|
||||
static IC: u32 = 29573;
|
||||
|
||||
static ALU: &'static str = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG\
|
||||
GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA\
|
||||
GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA\
|
||||
AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT\
|
||||
CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC\
|
||||
CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG\
|
||||
CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
|
||||
|
||||
static NULL_AMINO_ACID: AminoAcid = AminoAcid { c: ' ' as u8, p: 0.0 };
|
||||
|
||||
static MESSAGE_1: &'static str = ">ONE Homo sapiens alu\n";
|
||||
static MESSAGE_2: &'static str = ">TWO IUB ambiguity codes\n";
|
||||
static MESSAGE_3: &'static str = ">THREE Homo sapiens frequency\n";
|
||||
|
||||
static IUB: [AminoAcid, ..15] = [
|
||||
AminoAcid { c: 'a' as u8, p: 0.27 },
|
||||
AminoAcid { c: 'c' as u8, p: 0.12 },
|
||||
AminoAcid { c: 'g' as u8, p: 0.12 },
|
||||
AminoAcid { c: 't' as u8, p: 0.27 },
|
||||
AminoAcid { c: 'B' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'D' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'H' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'K' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'M' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'N' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'R' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'S' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'V' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'W' as u8, p: 0.02 },
|
||||
AminoAcid { c: 'Y' as u8, p: 0.02 },
|
||||
];
|
||||
|
||||
static HOMO_SAPIENS: [AminoAcid, ..4] = [
|
||||
AminoAcid { c: 'a' as u8, p: 0.3029549426680 },
|
||||
AminoAcid { c: 'c' as u8, p: 0.1979883004921 },
|
||||
AminoAcid { c: 'g' as u8, p: 0.1975473066391 },
|
||||
AminoAcid { c: 't' as u8, p: 0.3015094502008 },
|
||||
];
|
||||
|
||||
// XXX: Use map().
|
||||
fn sum_and_scale(a: &'static [AminoAcid]) -> ~[AminoAcid] {
|
||||
let mut result = ~[];
|
||||
let mut p = 0f32;
|
||||
for a.each |a_i| {
|
||||
let mut a_i = *a_i;
|
||||
p += a_i.p;
|
||||
a_i.p = p * LOOKUP_SCALE;
|
||||
result.push(a_i);
|
||||
}
|
||||
result[result.len() - 1].p = LOOKUP_SCALE;
|
||||
result
|
||||
}
|
||||
|
||||
struct AminoAcid {
|
||||
c: u8,
|
||||
p: f32,
|
||||
}
|
||||
|
||||
struct RepeatFasta {
|
||||
alu: &'static str,
|
||||
stdout: *FILE,
|
||||
}
|
||||
|
||||
impl RepeatFasta {
|
||||
fn new(stdout: *FILE, alu: &'static str) -> RepeatFasta {
|
||||
RepeatFasta {
|
||||
alu: alu,
|
||||
stdout: stdout,
|
||||
}
|
||||
}
|
||||
|
||||
fn make(&mut self, n: uint) {
|
||||
unsafe {
|
||||
let stdout = self.stdout;
|
||||
let alu_len = self.alu.len();
|
||||
let mut buf = vec::from_elem(alu_len + LINE_LEN, 0u8);
|
||||
let alu: &[u8] = str::byte_slice_no_callback(self.alu);
|
||||
|
||||
copy_memory(buf, alu, alu_len);
|
||||
copy_memory(vec::mut_slice(buf, alu_len, buf.len()),
|
||||
alu,
|
||||
LINE_LEN);
|
||||
|
||||
let mut pos = 0, bytes, n = n;
|
||||
while n > 0 {
|
||||
bytes = min(LINE_LEN, n);
|
||||
fwrite(transmute(&buf[pos]), bytes as u64, 1, stdout);
|
||||
fputc('\n' as c_int, stdout);
|
||||
pos += bytes;
|
||||
if pos > alu_len {
|
||||
pos -= alu_len;
|
||||
}
|
||||
n -= bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RandomFasta {
|
||||
seed: u32,
|
||||
stdout: *FILE,
|
||||
lookup: [AminoAcid, ..LOOKUP_SIZE],
|
||||
}
|
||||
|
||||
impl RandomFasta {
|
||||
fn new(stdout: *FILE, a: &[AminoAcid]) -> RandomFasta {
|
||||
RandomFasta {
|
||||
seed: 42,
|
||||
stdout: stdout,
|
||||
lookup: RandomFasta::make_lookup(a),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_lookup(a: &[AminoAcid]) -> [AminoAcid, ..LOOKUP_SIZE] {
|
||||
let mut lookup = [ NULL_AMINO_ACID, ..LOOKUP_SIZE ];
|
||||
let mut j = 0;
|
||||
for vec::eachi_mut(lookup) |i, slot| {
|
||||
while a[j].p < (i as f32) {
|
||||
j += 1;
|
||||
}
|
||||
*slot = a[j];
|
||||
}
|
||||
lookup
|
||||
}
|
||||
|
||||
fn rng(&mut self, max: f32) -> f32 {
|
||||
self.seed = (self.seed * IA + IC) % IM;
|
||||
max * (self.seed as f32) / (IM as f32)
|
||||
}
|
||||
|
||||
fn nextc(&mut self) -> u8 {
|
||||
let r = self.rng(1.0);
|
||||
for self.lookup.each |a| {
|
||||
if a.p >= r {
|
||||
return a.c;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
fn make(&mut self, n: uint) {
|
||||
unsafe {
|
||||
let lines = n / LINE_LEN, chars_left = n % LINE_LEN;
|
||||
let mut buf = [0, ..LINE_LEN + 1];
|
||||
|
||||
for lines.times {
|
||||
for range(0, LINE_LEN) |i| {
|
||||
buf[i] = self.nextc();
|
||||
}
|
||||
buf[LINE_LEN] = '\n' as u8;
|
||||
fwrite(transmute(&buf[0]),
|
||||
LINE_LEN as u64 + 1,
|
||||
1,
|
||||
self.stdout);
|
||||
}
|
||||
for range(0, chars_left) |i| {
|
||||
buf[i] = self.nextc();
|
||||
}
|
||||
fwrite(transmute(&buf[0]), chars_left as u64, 1, self.stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn main() {
|
||||
let n: uint = FromStr::from_str(os::args()[1]).get();
|
||||
|
||||
unsafe {
|
||||
let mode = "w";
|
||||
let stdout = fdopen(STDOUT_FILENO as c_int, transmute(&mode[0]));
|
||||
|
||||
fputs(transmute(&MESSAGE_1[0]), stdout);
|
||||
let mut repeat = RepeatFasta::new(stdout, ALU);
|
||||
repeat.make(n * 2);
|
||||
|
||||
fputs(transmute(&MESSAGE_2[0]), stdout);
|
||||
let iub = sum_and_scale(IUB);
|
||||
let mut random = RandomFasta::new(stdout, iub);
|
||||
random.make(n * 3);
|
||||
|
||||
fputs(transmute(&MESSAGE_3[0]), stdout);
|
||||
let homo_sapiens = sum_and_scale(HOMO_SAPIENS);
|
||||
random.lookup = RandomFasta::make_lookup(homo_sapiens);
|
||||
random.make(n * 5);
|
||||
|
||||
fputc('\n' as c_int, stdout);
|
||||
}
|
||||
}
|
||||
|
316
src/test/bench/shootout-k-nucleotide.rs
Normal file
316
src/test/bench/shootout-k-nucleotide.rs
Normal file
|
@ -0,0 +1,316 @@
|
|||
// xfail-test
|
||||
|
||||
extern mod std;
|
||||
|
||||
use core::cast::transmute;
|
||||
use core::i32::range;
|
||||
use core::libc::{STDIN_FILENO, c_int, fdopen, fgets, fileno, fopen, fstat};
|
||||
use core::libc::{stat, strlen};
|
||||
use core::ptr::null;
|
||||
use core::unstable::intrinsics::init;
|
||||
use core::vec::{reverse, slice};
|
||||
use std::sort::quick_sort3;
|
||||
|
||||
static LINE_LEN: uint = 80;
|
||||
static TABLE: [u8, ..4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
|
||||
static TABLE_SIZE: uint = 2 << 16;
|
||||
|
||||
static OCCURRENCES: [&'static str, ..5] = [
|
||||
"GGT",
|
||||
"GGTA",
|
||||
"GGTATT",
|
||||
"GGTATTTTAATT",
|
||||
"GGTATTTTAATTTATAGT",
|
||||
];
|
||||
|
||||
// Code implementation
|
||||
|
||||
#[deriving(Eq, Ord)]
|
||||
struct Code(u64);
|
||||
|
||||
impl Code {
|
||||
fn hash(&self) -> u64 {
|
||||
**self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn push_char(&self, c: u8) -> Code {
|
||||
Code((**self << 2) + (pack_symbol(c) as u64))
|
||||
}
|
||||
|
||||
fn rotate(&self, c: u8, frame: i32) -> Code {
|
||||
Code(*self.push_char(c) & ((1u64 << (2 * (frame as u64))) - 1))
|
||||
}
|
||||
|
||||
fn pack(string: &str) -> Code {
|
||||
let mut code = Code(0u64);
|
||||
for uint::range(0, string.len()) |i| {
|
||||
code = code.push_char(string[i]);
|
||||
}
|
||||
code
|
||||
}
|
||||
|
||||
// XXX: Inefficient.
|
||||
fn unpack(&self, frame: i32) -> ~str {
|
||||
let mut key = **self;
|
||||
let mut result = ~[];
|
||||
for (frame as uint).times {
|
||||
result.push(unpack_symbol((key as u8) & 3));
|
||||
key >>= 2;
|
||||
}
|
||||
|
||||
reverse(result);
|
||||
str::from_bytes(result)
|
||||
}
|
||||
}
|
||||
|
||||
// Hash table implementation
|
||||
|
||||
trait TableCallback {
|
||||
fn f(&self, entry: &mut Entry);
|
||||
}
|
||||
|
||||
struct BumpCallback;
|
||||
|
||||
impl TableCallback for BumpCallback {
|
||||
fn f(&self, entry: &mut Entry) {
|
||||
entry.count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct PrintCallback(&'static str);
|
||||
|
||||
impl TableCallback for PrintCallback {
|
||||
fn f(&self, entry: &mut Entry) {
|
||||
println(fmt!("%d\t%s", entry.count as int, **self));
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
code: Code,
|
||||
count: i32,
|
||||
next: Option<~Entry>,
|
||||
}
|
||||
|
||||
struct Table {
|
||||
count: i32,
|
||||
items: [Option<~Entry>, ..TABLE_SIZE]
|
||||
}
|
||||
|
||||
impl Table {
|
||||
fn new() -> Table {
|
||||
Table {
|
||||
count: 0,
|
||||
items: [ None, ..TABLE_SIZE ],
|
||||
}
|
||||
}
|
||||
|
||||
fn search_remainder<C:TableCallback>(item: &mut Entry, key: Code, c: C) {
|
||||
match item.next {
|
||||
None => {
|
||||
let mut entry = ~Entry {
|
||||
code: key,
|
||||
count: 0,
|
||||
next: None,
|
||||
};
|
||||
c.f(entry);
|
||||
item.next = Some(entry);
|
||||
}
|
||||
Some(ref mut entry) => {
|
||||
if entry.code == key {
|
||||
c.f(*entry);
|
||||
return;
|
||||
}
|
||||
|
||||
Table::search_remainder(*entry, key, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup<C:TableCallback>(&mut self, key: Code, c: C) {
|
||||
let index = *key % (TABLE_SIZE as u64);
|
||||
|
||||
{
|
||||
if self.items[index].is_none() {
|
||||
let mut entry = ~Entry {
|
||||
code: key,
|
||||
count: 0,
|
||||
next: None,
|
||||
};
|
||||
c.f(entry);
|
||||
self.items[index] = Some(entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut entry = &mut *self.items[index].get_mut_ref();
|
||||
if entry.code == key {
|
||||
c.f(*entry);
|
||||
return;
|
||||
}
|
||||
|
||||
Table::search_remainder(*entry, key, c)
|
||||
}
|
||||
}
|
||||
|
||||
fn each(&self, f: &fn(entry: &Entry) -> bool) {
|
||||
for self.items.each |item| {
|
||||
match *item {
|
||||
None => {}
|
||||
Some(ref item) => {
|
||||
let mut item: &Entry = *item;
|
||||
loop {
|
||||
if !f(item) {
|
||||
return;
|
||||
}
|
||||
|
||||
match item.next {
|
||||
None => break,
|
||||
Some(ref next_item) => item = &**next_item,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main program
|
||||
|
||||
fn pack_symbol(c: u8) -> u8 {
|
||||
match c {
|
||||
'a' as u8 | 'A' as u8 => 0,
|
||||
'c' as u8 | 'C' as u8 => 1,
|
||||
'g' as u8 | 'G' as u8 => 2,
|
||||
't' as u8 | 'T' as u8 => 3,
|
||||
_ => fail!(c.to_str())
|
||||
}
|
||||
}
|
||||
|
||||
fn unpack_symbol(c: u8) -> u8 {
|
||||
TABLE[c]
|
||||
}
|
||||
|
||||
fn next_char<'a>(mut buf: &'a [u8]) -> &'a [u8] {
|
||||
loop {
|
||||
buf = slice(buf, 1, buf.len());
|
||||
if buf.len() == 0 {
|
||||
break;
|
||||
}
|
||||
if buf[0] != (' ' as u8) && buf[0] != ('\t' as u8) &&
|
||||
buf[0] != ('\n' as u8) && buf[0] != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn read_stdin() -> ~[u8] {
|
||||
unsafe {
|
||||
let mode = "r";
|
||||
//let stdin = fdopen(STDIN_FILENO as c_int, transmute(&mode[0]));
|
||||
let path = "knucleotide-input.txt";
|
||||
let stdin = fopen(transmute(&path[0]), transmute(&mode[0]));
|
||||
|
||||
let mut st: stat = init();
|
||||
fstat(fileno(stdin), &mut st);
|
||||
let mut buf = vec::from_elem(st.st_size as uint, 0);
|
||||
|
||||
let header = str::byte_slice_no_callback(">THREE");
|
||||
let header = vec::slice(header, 0, 6);
|
||||
|
||||
{
|
||||
let mut window: &mut [u8] = buf;
|
||||
loop {
|
||||
fgets(transmute(&mut window[0]), LINE_LEN as c_int, stdin);
|
||||
|
||||
{
|
||||
if vec::slice(window, 0, 6) == header {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while fgets(transmute(&mut window[0]),
|
||||
LINE_LEN as c_int,
|
||||
stdin) != null() {
|
||||
window = vec::mut_slice(window,
|
||||
strlen(transmute(&window[0])) as uint,
|
||||
window.len());
|
||||
}
|
||||
}
|
||||
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[fixed_stack_segment]
|
||||
fn generate_frequencies(frequencies: &mut Table,
|
||||
mut input: &[u8],
|
||||
frame: i32) {
|
||||
let mut code = Code(0);
|
||||
|
||||
// Pull first frame.
|
||||
for (frame as uint).times {
|
||||
code = code.push_char(input[0]);
|
||||
input = next_char(input);
|
||||
}
|
||||
frequencies.lookup(code, BumpCallback);
|
||||
|
||||
while input.len() != 0 && input[0] != ('>' as u8) {
|
||||
code = code.rotate(input[0], frame);
|
||||
frequencies.lookup(code, BumpCallback);
|
||||
input = next_char(input);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[fixed_stack_segment]
|
||||
fn print_frequencies(frequencies: &Table, frame: i32) {
|
||||
let mut vector = ~[];
|
||||
for frequencies.each |entry| {
|
||||
vector.push((entry.code, entry.count));
|
||||
}
|
||||
quick_sort3(vector);
|
||||
|
||||
let mut total_count = 0;
|
||||
for vector.each |&(_, count)| {
|
||||
total_count += count;
|
||||
}
|
||||
|
||||
for vector.each |&(key, count)| {
|
||||
println(fmt!("%s %.3f",
|
||||
key.unpack(frame),
|
||||
(count as float * 100.0) / (total_count as float)));
|
||||
}
|
||||
}
|
||||
|
||||
fn print_occurrences(frequencies: &mut Table, occurrence: &'static str) {
|
||||
frequencies.lookup(Code::pack(occurrence), PrintCallback(occurrence))
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn main() {
|
||||
let input = read_stdin();
|
||||
|
||||
let mut frequencies = ~Table::new();
|
||||
generate_frequencies(frequencies, input, 1);
|
||||
print_frequencies(frequencies, 1);
|
||||
|
||||
*frequencies = Table::new();
|
||||
generate_frequencies(frequencies, input, 2);
|
||||
print_frequencies(frequencies, 2);
|
||||
|
||||
for range(0, 5) |i| {
|
||||
let occurrence = OCCURRENCES[i];
|
||||
*frequencies = Table::new();
|
||||
generate_frequencies(frequencies,
|
||||
input,
|
||||
occurrence.len() as i32);
|
||||
print_occurrences(frequencies, occurrence);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,182 +1,60 @@
|
|||
// Copyright 2012-2013 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.
|
||||
use core::cast::transmute;
|
||||
use core::from_str::FromStr;
|
||||
use core::i32::range;
|
||||
use core::libc::{STDOUT_FILENO, c_int, fdopen, fputc};
|
||||
|
||||
// based on:
|
||||
// http://shootout.alioth.debian.org/
|
||||
// u64q/program.php?test=mandelbrot&lang=python3&id=2
|
||||
//
|
||||
// takes 3 optional args:
|
||||
// square image size, defaults to 80_u
|
||||
// output path, default is "" (no output), "-" means stdout
|
||||
// depth (max iterations per pixel), defaults to 50_u
|
||||
//
|
||||
// in the shootout, they use 16000 as image size, 50 as depth,
|
||||
// and write to stdout:
|
||||
//
|
||||
// ./shootout_mandelbrot 16000 "-" 50 > /tmp/mandel.pbm
|
||||
//
|
||||
// writes pbm image to output path
|
||||
|
||||
use core::io::WriterUtil;
|
||||
use core::hashmap::HashMap;
|
||||
|
||||
struct cmplx {
|
||||
re: f64,
|
||||
im: f64
|
||||
}
|
||||
|
||||
impl ops::Mul<cmplx,cmplx> for cmplx {
|
||||
fn mul(&self, x: &cmplx) -> cmplx {
|
||||
cmplx {
|
||||
re: self.re*(*x).re - self.im*(*x).im,
|
||||
im: self.re*(*x).im + self.im*(*x).re
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Add<cmplx,cmplx> for cmplx {
|
||||
fn add(&self, x: &cmplx) -> cmplx {
|
||||
cmplx {
|
||||
re: self.re + (*x).re,
|
||||
im: self.im + (*x).im
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Line {i: uint, b: ~[u8]}
|
||||
|
||||
fn cabs(x: cmplx) -> f64
|
||||
{
|
||||
x.re*x.re + x.im*x.im
|
||||
}
|
||||
|
||||
fn mb(x: cmplx, depth: uint) -> bool
|
||||
{
|
||||
let mut z = x;
|
||||
let mut i = 0;
|
||||
while i < depth {
|
||||
if cabs(z) >= 4_f64 {
|
||||
return false;
|
||||
}
|
||||
z = z*z + x;
|
||||
i += 1;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn fillbyte(x: cmplx, incr: f64, depth: uint) -> u8 {
|
||||
let mut rv = 0_u8;
|
||||
let mut i = 0_u8;
|
||||
while i < 8_u8 {
|
||||
let z = cmplx {re: x.re + (i as f64)*incr, im: x.im};
|
||||
if mb(z, depth) {
|
||||
rv += 1_u8 << (7_u8 - i);
|
||||
}
|
||||
i += 1_u8;
|
||||
}
|
||||
rv
|
||||
}
|
||||
|
||||
fn chanmb(i: uint, size: uint, depth: uint) -> Line
|
||||
{
|
||||
let bsize = size/8_u;
|
||||
let mut crv = vec::with_capacity(bsize);
|
||||
let incr = 2_f64/(size as f64);
|
||||
let y = incr*(i as f64) - 1_f64;
|
||||
let xincr = 8_f64*incr;
|
||||
for uint::range(0_u, bsize) |j| {
|
||||
let x = cmplx {re: xincr*(j as f64) - 1.5_f64, im: y};
|
||||
crv.push(fillbyte(x, incr, depth));
|
||||
};
|
||||
Line {i:i, b:crv}
|
||||
}
|
||||
|
||||
struct Devnull();
|
||||
|
||||
impl io::Writer for Devnull {
|
||||
fn write(&self, _b: &const [u8]) {}
|
||||
fn seek(&self, _i: int, _s: io::SeekStyle) {}
|
||||
fn tell(&self) -> uint {0_u}
|
||||
fn flush(&self) -> int {0}
|
||||
fn get_type(&self) -> io::WriterType { io::File }
|
||||
}
|
||||
|
||||
fn writer(path: ~str, pport: comm::Port<Line>, size: uint)
|
||||
{
|
||||
let cout: @io::Writer = match path {
|
||||
~"" => {
|
||||
@Devnull as @io::Writer
|
||||
}
|
||||
~"-" => {
|
||||
io::stdout()
|
||||
}
|
||||
_ => {
|
||||
result::get(
|
||||
&io::file_writer(&Path(path),
|
||||
~[io::Create, io::Truncate]))
|
||||
}
|
||||
};
|
||||
cout.write_line("P4");
|
||||
cout.write_line(fmt!("%u %u", size, size));
|
||||
let mut lines: HashMap<uint, Line> = HashMap::new();
|
||||
let mut done = 0_u;
|
||||
let mut i = 0_u;
|
||||
while i < size {
|
||||
let aline = pport.recv();
|
||||
if aline.i == done {
|
||||
debug!("W %u", done);
|
||||
cout.write(aline.b);
|
||||
done += 1_u;
|
||||
let mut prev = done;
|
||||
while prev <= i {
|
||||
match lines.pop(&prev) {
|
||||
Some(pl) => {
|
||||
debug!("WS %u", prev);
|
||||
cout.write(pl.b);
|
||||
done += 1_u;
|
||||
prev += 1_u;
|
||||
}
|
||||
None => break
|
||||
};
|
||||
};
|
||||
}
|
||||
else {
|
||||
debug!("S %u", aline.i);
|
||||
lines.insert(aline.i, aline);
|
||||
};
|
||||
i += 1_u;
|
||||
}
|
||||
}
|
||||
static ITER: uint = 50;
|
||||
static LIMIT: f64 = 2.0;
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
let args = if os::getenv(~"RUST_BENCH").is_some() {
|
||||
~[~"", ~"4000", ~"50"]
|
||||
} else {
|
||||
args
|
||||
};
|
||||
unsafe {
|
||||
let w: i32 = FromStr::from_str(os::args()[1]).get(), h = w;
|
||||
let mut byte_acc: i8 = 0;
|
||||
let mut bit_num: i32 = 0;
|
||||
|
||||
let depth = if vec::len(args) < 4_u { 50_u }
|
||||
else { uint::from_str(args[3]).get() };
|
||||
println(fmt!("P4\n%d %d", w as int, h as int));
|
||||
|
||||
let path = if vec::len(args) < 3_u { ~"" }
|
||||
else { copy args[2] }; // FIXME: bad for perf
|
||||
let mode = "w";
|
||||
let stdout = fdopen(STDOUT_FILENO as c_int, transmute(&mode[0]));
|
||||
|
||||
let size = if vec::len(args) < 2_u { 80_u }
|
||||
else { uint::from_str(args[1]).get() };
|
||||
for range(0, h) |y| {
|
||||
let y = y as f64;
|
||||
for range(0, w) |x| {
|
||||
let mut (Zr, Zi, Tr, Ti) = (0f64, 0f64, 0f64, 0f64);
|
||||
let Cr = 2.0 * (x as f64) / (w as f64) - 1.5;
|
||||
let Ci = 2.0 * (y as f64) / (h as f64) - 1.0;
|
||||
|
||||
let (pport, pchan) = comm::stream();
|
||||
let pchan = comm::SharedChan::new(pchan);
|
||||
for uint::range(0_u, size) |j| {
|
||||
let cchan = pchan.clone();
|
||||
do task::spawn { cchan.send(chanmb(j, size, depth)) };
|
||||
};
|
||||
writer(path, pport, size);
|
||||
for ITER.times {
|
||||
if Tr + Ti > LIMIT * LIMIT {
|
||||
break;
|
||||
}
|
||||
|
||||
Zi = 2.0*Zr*Zi + Ci;
|
||||
Zr = Tr - Ti + Cr;
|
||||
Tr = Zr * Zr;
|
||||
Ti = Zi * Zi;
|
||||
}
|
||||
|
||||
byte_acc <<= 1;
|
||||
if Tr + Ti <= LIMIT * LIMIT {
|
||||
byte_acc |= 1;
|
||||
}
|
||||
|
||||
bit_num += 1;
|
||||
|
||||
if bit_num == 8 {
|
||||
fputc(byte_acc as c_int, stdout);
|
||||
byte_acc = 0;
|
||||
bit_num = 0;
|
||||
} else if x == w - 1 {
|
||||
byte_acc <<= 8 - w%8;
|
||||
fputc(byte_acc as c_int, stdout);
|
||||
byte_acc = 0;
|
||||
bit_num = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,254 +1,150 @@
|
|||
// 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.
|
||||
use core::from_str::FromStr;
|
||||
use core::uint::range;
|
||||
use core::unstable::intrinsics::sqrtf64;
|
||||
|
||||
// based on:
|
||||
// http://shootout.alioth.debian.org/u32/benchmark.php?test=nbody&lang=java
|
||||
static PI: f64 = 3.141592653589793;
|
||||
static SOLAR_MASS: f64 = 4.0 * PI * PI;
|
||||
static YEAR: f64 = 365.24;
|
||||
static N_BODIES: uint = 5;
|
||||
|
||||
extern mod std;
|
||||
static BODIES: [Planet, ..N_BODIES] = [
|
||||
// Sun
|
||||
Planet {
|
||||
x: [ 0.0, 0.0, 0.0 ],
|
||||
v: [ 0.0, 0.0, 0.0 ],
|
||||
mass: SOLAR_MASS,
|
||||
},
|
||||
// Jupiter
|
||||
Planet {
|
||||
x: [
|
||||
4.84143144246472090e+00,
|
||||
-1.16032004402742839e+00,
|
||||
-1.03622044471123109e-01,
|
||||
],
|
||||
v: [
|
||||
1.66007664274403694e-03 * YEAR,
|
||||
7.69901118419740425e-03 * YEAR,
|
||||
-6.90460016972063023e-05 * YEAR,
|
||||
],
|
||||
mass: 9.54791938424326609e-04 * SOLAR_MASS,
|
||||
},
|
||||
// Saturn
|
||||
Planet {
|
||||
x: [
|
||||
8.34336671824457987e+00,
|
||||
4.12479856412430479e+00,
|
||||
-4.03523417114321381e-01,
|
||||
],
|
||||
v: [
|
||||
-2.76742510726862411e-03 * YEAR,
|
||||
4.99852801234917238e-03 * YEAR,
|
||||
2.30417297573763929e-05 * YEAR,
|
||||
],
|
||||
mass: 2.85885980666130812e-04 * SOLAR_MASS,
|
||||
},
|
||||
// Uranus
|
||||
Planet {
|
||||
x: [
|
||||
1.28943695621391310e+01,
|
||||
-1.51111514016986312e+01,
|
||||
-2.23307578892655734e-01,
|
||||
],
|
||||
v: [
|
||||
2.96460137564761618e-03 * YEAR,
|
||||
2.37847173959480950e-03 * YEAR,
|
||||
-2.96589568540237556e-05 * YEAR,
|
||||
],
|
||||
mass: 4.36624404335156298e-05 * SOLAR_MASS,
|
||||
},
|
||||
// Neptune
|
||||
Planet {
|
||||
x: [
|
||||
1.53796971148509165e+01,
|
||||
-2.59193146099879641e+01,
|
||||
1.79258772950371181e-01,
|
||||
],
|
||||
v: [
|
||||
2.68067772490389322e-03 * YEAR,
|
||||
1.62824170038242295e-03 * YEAR,
|
||||
-9.51592254519715870e-05 * YEAR,
|
||||
],
|
||||
mass: 5.15138902046611451e-05 * SOLAR_MASS,
|
||||
},
|
||||
];
|
||||
|
||||
use core::os;
|
||||
struct Planet {
|
||||
x: [f64, ..3],
|
||||
v: [f64, ..3],
|
||||
mass: f64,
|
||||
}
|
||||
|
||||
// Using sqrt from the standard library is way slower than using libc
|
||||
// directly even though std just calls libc, I guess it must be
|
||||
// because the the indirection through another dynamic linker
|
||||
// stub. Kind of shocking. Might be able to make it faster still with
|
||||
// an llvm intrinsic.
|
||||
mod libc {
|
||||
#[nolink]
|
||||
pub extern {
|
||||
pub fn sqrt(n: float) -> float;
|
||||
fn advance(bodies: &mut [Planet, ..N_BODIES], dt: f64, steps: i32) {
|
||||
let mut d = [ 0.0, ..3 ];
|
||||
for (steps as uint).times {
|
||||
for range(0, N_BODIES) |i| {
|
||||
for range(i + 1, N_BODIES) |j| {
|
||||
d[0] = bodies[i].x[0] - bodies[j].x[0];
|
||||
d[1] = bodies[i].x[1] - bodies[j].x[1];
|
||||
d[2] = bodies[i].x[2] - bodies[j].x[2];
|
||||
|
||||
let d2 = d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
|
||||
let mag = dt / (d2 * sqrtf64(d2));
|
||||
|
||||
let a_mass = bodies[i].mass, b_mass = bodies[j].mass;
|
||||
bodies[i].v[0] -= d[0] * b_mass * mag;
|
||||
bodies[i].v[1] -= d[1] * b_mass * mag;
|
||||
bodies[i].v[2] -= d[2] * b_mass * mag;
|
||||
|
||||
bodies[j].v[0] += d[0] * a_mass * mag;
|
||||
bodies[j].v[1] += d[1] * a_mass * mag;
|
||||
bodies[j].v[2] += d[2] * a_mass * mag;
|
||||
}
|
||||
}
|
||||
|
||||
for vec::each_mut(*bodies) |a| {
|
||||
a.x[0] += dt * a.v[0];
|
||||
a.x[1] += dt * a.v[1];
|
||||
a.x[2] += dt * a.v[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn energy(bodies: &[Planet, ..N_BODIES]) -> f64 {
|
||||
let mut e = 0.0;
|
||||
let mut d = [ 0.0, ..3 ];
|
||||
for range(0, N_BODIES) |i| {
|
||||
for range(0, 3) |k| {
|
||||
e += bodies[i].mass * bodies[i].v[k] * bodies[i].v[k] / 2.0;
|
||||
}
|
||||
|
||||
for range(i + 1, N_BODIES) |j| {
|
||||
for range(0, 3) |k| {
|
||||
d[k] = bodies[i].x[k] - bodies[j].x[k];
|
||||
}
|
||||
let dist = sqrtf64(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]);
|
||||
e -= bodies[i].mass * bodies[j].mass / dist;
|
||||
}
|
||||
}
|
||||
e
|
||||
}
|
||||
|
||||
fn offset_momentum(bodies: &mut [Planet, ..N_BODIES]) {
|
||||
for range(0, N_BODIES) |i| {
|
||||
for range(0, 3) |k| {
|
||||
bodies[0].v[k] -= bodies[i].v[k] * bodies[i].mass / SOLAR_MASS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
let args = if os::getenv(~"RUST_BENCH").is_some() {
|
||||
~[~"", ~"4000000"]
|
||||
} else if args.len() <= 1u {
|
||||
~[~"", ~"100000"]
|
||||
} else {
|
||||
args
|
||||
};
|
||||
let n = int::from_str(args[1]).get();
|
||||
let mut bodies: ~[Body::Props] = NBodySystem::make();
|
||||
io::println(fmt!("%f", NBodySystem::energy(bodies)));
|
||||
let mut i = 0;
|
||||
while i < n {
|
||||
NBodySystem::advance(bodies, 0.01);
|
||||
i += 1;
|
||||
}
|
||||
io::println(fmt!("%f", NBodySystem::energy(bodies)));
|
||||
let n: i32 = FromStr::from_str(os::args()[1]).get();
|
||||
let mut bodies = BODIES;
|
||||
|
||||
offset_momentum(&mut bodies);
|
||||
println(fmt!("%.9f", energy(&bodies) as float));
|
||||
|
||||
advance(&mut bodies, 0.01, n);
|
||||
|
||||
println(fmt!("%.9f", energy(&bodies) as float));
|
||||
}
|
||||
|
||||
pub mod NBodySystem {
|
||||
use Body;
|
||||
|
||||
pub fn make() -> ~[Body::Props] {
|
||||
let mut bodies: ~[Body::Props] =
|
||||
~[Body::sun(),
|
||||
Body::jupiter(),
|
||||
Body::saturn(),
|
||||
Body::uranus(),
|
||||
Body::neptune()];
|
||||
|
||||
let mut px = 0.0;
|
||||
let mut py = 0.0;
|
||||
let mut pz = 0.0;
|
||||
|
||||
let mut i = 0;
|
||||
while i < 5 {
|
||||
px += bodies[i].vx * bodies[i].mass;
|
||||
py += bodies[i].vy * bodies[i].mass;
|
||||
pz += bodies[i].vz * bodies[i].mass;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// side-effecting
|
||||
Body::offset_momentum(&mut bodies[0], px, py, pz);
|
||||
|
||||
return bodies;
|
||||
}
|
||||
|
||||
pub fn advance(bodies: &mut [Body::Props], dt: float) {
|
||||
let mut i = 0;
|
||||
while i < 5 {
|
||||
let mut j = i + 1;
|
||||
while j < 5 {
|
||||
advance_one(&mut bodies[i],
|
||||
&mut bodies[j], dt);
|
||||
j += 1;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while i < 5 {
|
||||
move_(&mut bodies[i], dt);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn advance_one(bi: &mut Body::Props,
|
||||
bj: &mut Body::Props,
|
||||
dt: float) {
|
||||
unsafe {
|
||||
let dx = bi.x - bj.x;
|
||||
let dy = bi.y - bj.y;
|
||||
let dz = bi.z - bj.z;
|
||||
|
||||
let dSquared = dx * dx + dy * dy + dz * dz;
|
||||
|
||||
let distance = ::libc::sqrt(dSquared);
|
||||
let mag = dt / (dSquared * distance);
|
||||
|
||||
bi.vx -= dx * bj.mass * mag;
|
||||
bi.vy -= dy * bj.mass * mag;
|
||||
bi.vz -= dz * bj.mass * mag;
|
||||
|
||||
bj.vx += dx * bi.mass * mag;
|
||||
bj.vy += dy * bi.mass * mag;
|
||||
bj.vz += dz * bi.mass * mag;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_(b: &mut Body::Props, dt: float) {
|
||||
b.x += dt * b.vx;
|
||||
b.y += dt * b.vy;
|
||||
b.z += dt * b.vz;
|
||||
}
|
||||
|
||||
pub fn energy(bodies: &[Body::Props]) -> float {
|
||||
unsafe {
|
||||
let mut dx;
|
||||
let mut dy;
|
||||
let mut dz;
|
||||
let mut distance;
|
||||
let mut e = 0.0;
|
||||
|
||||
let mut i = 0;
|
||||
while i < 5 {
|
||||
e +=
|
||||
0.5 * bodies[i].mass *
|
||||
(bodies[i].vx * bodies[i].vx
|
||||
+ bodies[i].vy * bodies[i].vy
|
||||
+ bodies[i].vz * bodies[i].vz);
|
||||
|
||||
let mut j = i + 1;
|
||||
while j < 5 {
|
||||
dx = bodies[i].x - bodies[j].x;
|
||||
dy = bodies[i].y - bodies[j].y;
|
||||
dz = bodies[i].z - bodies[j].z;
|
||||
|
||||
distance = ::libc::sqrt(dx * dx
|
||||
+ dy * dy
|
||||
+ dz * dz);
|
||||
e -= bodies[i].mass
|
||||
* bodies[j].mass / distance;
|
||||
|
||||
j += 1;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod Body {
|
||||
use Body;
|
||||
|
||||
pub static PI: float = 3.141592653589793;
|
||||
pub static SOLAR_MASS: float = 39.478417604357432;
|
||||
// was 4 * PI * PI originally
|
||||
pub static DAYS_PER_YEAR: float = 365.24;
|
||||
|
||||
pub struct Props {
|
||||
x: float,
|
||||
y: float,
|
||||
z: float,
|
||||
vx: float,
|
||||
vy: float,
|
||||
vz: float,
|
||||
mass: float
|
||||
}
|
||||
|
||||
pub fn jupiter() -> Body::Props {
|
||||
return Props {
|
||||
x: 4.84143144246472090e+00,
|
||||
y: -1.16032004402742839e+00,
|
||||
z: -1.03622044471123109e-01,
|
||||
vx: 1.66007664274403694e-03 * DAYS_PER_YEAR,
|
||||
vy: 7.69901118419740425e-03 * DAYS_PER_YEAR,
|
||||
vz: -6.90460016972063023e-05 * DAYS_PER_YEAR,
|
||||
mass: 9.54791938424326609e-04 * SOLAR_MASS
|
||||
};
|
||||
}
|
||||
|
||||
pub fn saturn() -> Body::Props {
|
||||
return Props {
|
||||
x: 8.34336671824457987e+00,
|
||||
y: 4.12479856412430479e+00,
|
||||
z: -4.03523417114321381e-01,
|
||||
vx: -2.76742510726862411e-03 * DAYS_PER_YEAR,
|
||||
vy: 4.99852801234917238e-03 * DAYS_PER_YEAR,
|
||||
vz: 2.30417297573763929e-05 * DAYS_PER_YEAR,
|
||||
mass: 2.85885980666130812e-04 * SOLAR_MASS
|
||||
};
|
||||
}
|
||||
|
||||
pub fn uranus() -> Body::Props {
|
||||
return Props {
|
||||
x: 1.28943695621391310e+01,
|
||||
y: -1.51111514016986312e+01,
|
||||
z: -2.23307578892655734e-01,
|
||||
vx: 2.96460137564761618e-03 * DAYS_PER_YEAR,
|
||||
vy: 2.37847173959480950e-03 * DAYS_PER_YEAR,
|
||||
vz: -2.96589568540237556e-05 * DAYS_PER_YEAR,
|
||||
mass: 4.36624404335156298e-05 * SOLAR_MASS
|
||||
};
|
||||
}
|
||||
|
||||
pub fn neptune() -> Body::Props {
|
||||
return Props {
|
||||
x: 1.53796971148509165e+01,
|
||||
y: -2.59193146099879641e+01,
|
||||
z: 1.79258772950371181e-01,
|
||||
vx: 2.68067772490389322e-03 * DAYS_PER_YEAR,
|
||||
vy: 1.62824170038242295e-03 * DAYS_PER_YEAR,
|
||||
vz: -9.51592254519715870e-05 * DAYS_PER_YEAR,
|
||||
mass: 5.15138902046611451e-05 * SOLAR_MASS
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sun() -> Body::Props {
|
||||
return Props {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
vx: 0.0,
|
||||
vy: 0.0,
|
||||
vz: 0.0,
|
||||
mass: SOLAR_MASS
|
||||
};
|
||||
}
|
||||
|
||||
pub fn offset_momentum(props: &mut Body::Props,
|
||||
px: float,
|
||||
py: float,
|
||||
pz: float) {
|
||||
props.vx = -px / SOLAR_MASS;
|
||||
props.vy = -py / SOLAR_MASS;
|
||||
props.vz = -pz / SOLAR_MASS;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
178
src/test/bench/shootout-pidigits.rs
Normal file
178
src/test/bench/shootout-pidigits.rs
Normal file
|
@ -0,0 +1,178 @@
|
|||
// xfail-test
|
||||
|
||||
use core::cast::transmute;
|
||||
use core::from_str::FromStr;
|
||||
use core::libc::{STDOUT_FILENO, c_char, c_int, c_uint, c_void, fdopen, fputc};
|
||||
use core::libc::{fputs};
|
||||
use core::ptr::null;
|
||||
|
||||
struct mpz_t {
|
||||
_mp_alloc: c_int,
|
||||
_mp_size: c_int,
|
||||
_mp_limb_t: *c_void,
|
||||
}
|
||||
|
||||
impl mpz_t {
|
||||
fn new() -> mpz_t {
|
||||
mpz_t {
|
||||
_mp_alloc: 0,
|
||||
_mp_size: 0,
|
||||
_mp_limb_t: null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[link_args="-lgmp"]
|
||||
extern {
|
||||
#[fast_ffi]
|
||||
#[link_name="__gmpz_add"]
|
||||
fn mpz_add(x: *mpz_t, y: *mpz_t, z: *mpz_t);
|
||||
#[fast_ffi]
|
||||
#[link_name="__gmpz_cmp"]
|
||||
fn mpz_cmp(x: *mpz_t, y: *mpz_t) -> c_int;
|
||||
#[fast_ffi]
|
||||
#[link_name="__gmpz_fdiv_qr"]
|
||||
fn mpz_fdiv_qr(a: *mpz_t, b: *mpz_t, c: *mpz_t, d: *mpz_t);
|
||||
#[fast_ffi]
|
||||
#[link_name="__gmpz_get_ui"]
|
||||
fn mpz_get_ui(x: *mpz_t) -> c_uint;
|
||||
#[fast_ffi]
|
||||
#[link_name="__gmpz_init"]
|
||||
fn mpz_init(x: *mpz_t);
|
||||
#[fast_ffi]
|
||||
#[link_name="__gmpz_init_set_ui"]
|
||||
fn mpz_init_set_ui(x: *mpz_t, y: c_uint);
|
||||
#[fast_ffi]
|
||||
#[link_name="__gmpz_mul_2exp"]
|
||||
fn mpz_mul_2exp(x: *mpz_t, y: *mpz_t, z: c_uint);
|
||||
#[fast_ffi]
|
||||
#[link_name="__gmpz_mul_ui"]
|
||||
fn mpz_mul_ui(x: *mpz_t, y: *mpz_t, z: c_uint);
|
||||
#[fast_ffi]
|
||||
#[link_name="__gmpz_submul_ui"]
|
||||
fn mpz_submul_ui(x: *mpz_t, y: *mpz_t, z: c_uint);
|
||||
}
|
||||
|
||||
struct Context {
|
||||
numer: mpz_t,
|
||||
accum: mpz_t,
|
||||
denom: mpz_t,
|
||||
tmp1: mpz_t,
|
||||
tmp2: mpz_t,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
fn new() -> Context {
|
||||
unsafe {
|
||||
let mut result = Context {
|
||||
numer: mpz_t::new(),
|
||||
accum: mpz_t::new(),
|
||||
denom: mpz_t::new(),
|
||||
tmp1: mpz_t::new(),
|
||||
tmp2: mpz_t::new(),
|
||||
};
|
||||
mpz_init(&result.tmp1);
|
||||
mpz_init(&result.tmp2);
|
||||
mpz_init_set_ui(&result.numer, 1);
|
||||
mpz_init_set_ui(&result.accum, 0);
|
||||
mpz_init_set_ui(&result.denom, 1);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_digit(&mut self) -> i32 {
|
||||
unsafe {
|
||||
if mpz_cmp(&self.numer, &self.accum) > 0 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Compute (numer * 3 + accum) / denom
|
||||
mpz_mul_2exp(&self.tmp1, &self.numer, 1);
|
||||
mpz_add(&self.tmp1, &self.tmp1, &self.numer);
|
||||
mpz_add(&self.tmp1, &self.tmp1, &self.accum);
|
||||
mpz_fdiv_qr(&self.tmp1, &self.tmp2, &self.tmp1, &self.denom);
|
||||
|
||||
// Now, if (numer * 4 + accum) % denom...
|
||||
mpz_add(&self.tmp2, &self.tmp2, &self.numer);
|
||||
|
||||
// ... is normalized, then the two divisions have the same result.
|
||||
if mpz_cmp(&self.tmp2, &self.denom) >= 0 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mpz_get_ui(&self.tmp1) as i32
|
||||
}
|
||||
}
|
||||
|
||||
fn next_term(&mut self, k: u32) {
|
||||
unsafe {
|
||||
let y2 = k*2 + 1;
|
||||
|
||||
mpz_mul_2exp(&self.tmp1, &self.numer, 1);
|
||||
mpz_add(&self.accum, &self.accum, &self.tmp1);
|
||||
mpz_mul_ui(&self.accum, &self.accum, y2);
|
||||
mpz_mul_ui(&self.numer, &self.numer, k);
|
||||
mpz_mul_ui(&self.denom, &self.denom, y2);
|
||||
}
|
||||
}
|
||||
|
||||
fn eliminate_digit(&mut self, d: u32) {
|
||||
unsafe {
|
||||
mpz_submul_ui(&self.accum, &self.denom, d);
|
||||
mpz_mul_ui(&self.accum, &self.accum, 10);
|
||||
mpz_mul_ui(&self.numer, &self.numer, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pidigits(n: u32) {
|
||||
unsafe {
|
||||
let mode = "w";
|
||||
let stdout = fdopen(STDOUT_FILENO as c_int, transmute(&mode[0]));
|
||||
|
||||
let mut d: i32;
|
||||
let mut i: u32 = 0, k: u32 = 0, m: u32;
|
||||
|
||||
let mut context = Context::new();
|
||||
loop {
|
||||
loop {
|
||||
k += 1;
|
||||
context.next_term(k);
|
||||
d = context.extract_digit();
|
||||
if d != -1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fputc((d as c_int) + ('0' as c_int), stdout);
|
||||
|
||||
i += 1;
|
||||
m = i % 10;
|
||||
if m == 0 {
|
||||
let res = fmt!("\t:%d\n", i as int);
|
||||
fputs(transmute(&res[0]), stdout);
|
||||
}
|
||||
if i >= n {
|
||||
break;
|
||||
}
|
||||
context.eliminate_digit(d as u32);
|
||||
}
|
||||
|
||||
if m != 0 {
|
||||
m = 10 - m;
|
||||
while m != 0 {
|
||||
m -= 1;
|
||||
fputc(' ' as c_int, stdout);
|
||||
}
|
||||
let res = fmt!("\t:%d\n", i as int);
|
||||
fputs(transmute(&res[0]), stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn main() {
|
||||
let n: u32 = FromStr::from_str(os::args()[1]).get();
|
||||
pidigits(n);
|
||||
}
|
||||
|
155
src/test/bench/shootout-reverse-complement.rs
Normal file
155
src/test/bench/shootout-reverse-complement.rs
Normal file
|
@ -0,0 +1,155 @@
|
|||
// xfail-pretty
|
||||
// xfail-test
|
||||
|
||||
use core::cast::transmute;
|
||||
use core::libc::{STDOUT_FILENO, c_int, fdopen, fgets, fopen, fputc, fwrite};
|
||||
use core::libc::{size_t};
|
||||
use core::ptr::null;
|
||||
use core::vec::{capacity, reserve, reserve_at_least};
|
||||
use core::vec::raw::set_len;
|
||||
|
||||
static LINE_LEN: u32 = 80;
|
||||
|
||||
static COMPLEMENTS: [u8, ..256] = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0,
|
||||
'T' as u8,
|
||||
'V' as u8,
|
||||
'G' as u8,
|
||||
'H' as u8,
|
||||
0,
|
||||
0,
|
||||
'C' as u8,
|
||||
'D' as u8,
|
||||
0,
|
||||
0,
|
||||
'M' as u8,
|
||||
0,
|
||||
'K' as u8,
|
||||
'N' as u8,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
'Y' as u8,
|
||||
'S' as u8,
|
||||
'A' as u8,
|
||||
'A' as u8,
|
||||
'B' as u8,
|
||||
'W' as u8,
|
||||
0,
|
||||
'R' as u8,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
0,
|
||||
'T' as u8,
|
||||
'V' as u8,
|
||||
'G' as u8,
|
||||
'H' as u8,
|
||||
0,
|
||||
0,
|
||||
'C' as u8,
|
||||
'D' as u8,
|
||||
0,
|
||||
0,
|
||||
'M' as u8,
|
||||
0,
|
||||
'K' as u8,
|
||||
'N' as u8,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
'Y' as u8,
|
||||
'S' as u8,
|
||||
'A' as u8,
|
||||
'A' as u8,
|
||||
'B' as u8,
|
||||
'W' as u8,
|
||||
0,
|
||||
'R' as u8,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mode = "r";
|
||||
//let stdin = fdopen(STDIN_FILENO as c_int, transmute(&mode[0]));
|
||||
let path = "reversecomplement-input.txt";
|
||||
let stdin = fopen(transmute(&path[0]), transmute(&mode[0]));
|
||||
let mode = "w";
|
||||
let stdout = fdopen(STDOUT_FILENO as c_int, transmute(&mode[0]));
|
||||
|
||||
let mut out: ~[u8] = ~[];
|
||||
reserve(&mut out, 12777888);
|
||||
let mut pos = 0;
|
||||
|
||||
loop {
|
||||
let needed = pos + (LINE_LEN as uint) + 1;
|
||||
if capacity(&out) < needed {
|
||||
reserve_at_least(&mut out, needed);
|
||||
}
|
||||
|
||||
let mut ptr = out.unsafe_mut_ref(pos);
|
||||
if fgets(transmute(ptr), LINE_LEN as c_int, stdin) == null() {
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't change lines that begin with '>' or ';'.
|
||||
let first = *ptr;
|
||||
if first == ('>' as u8) {
|
||||
while *ptr != 0 {
|
||||
ptr = ptr.offset(1);
|
||||
}
|
||||
*ptr = '\n' as u8;
|
||||
|
||||
pos = (ptr as uint) - (out.unsafe_ref(0) as uint);
|
||||
fwrite(transmute(out.unsafe_ref(0)),
|
||||
1,
|
||||
pos as size_t,
|
||||
stdout);
|
||||
|
||||
pos = 0;
|
||||
loop;
|
||||
}
|
||||
|
||||
// Complement other lines.
|
||||
loop {
|
||||
let ch = *ptr;
|
||||
if ch == 0 {
|
||||
break;
|
||||
}
|
||||
*ptr = COMPLEMENTS.unsafe_get(ch as uint);
|
||||
ptr = ptr.offset(1);
|
||||
}
|
||||
*ptr = '\n' as u8;
|
||||
|
||||
pos = (ptr as uint) - (out.unsafe_ref(0) as uint);
|
||||
}
|
||||
|
||||
fwrite(transmute(out.unsafe_ref(0)), 1, pos as size_t, stdout);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +1,54 @@
|
|||
// 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.
|
||||
use core::from_str::FromStr;
|
||||
use core::iter::ExtendedMutableIter;
|
||||
use core::unstable::intrinsics::sqrtf64;
|
||||
|
||||
// Based on spectalnorm.gcc by Sebastien Loisel
|
||||
|
||||
extern mod std;
|
||||
|
||||
fn eval_A(i: uint, j: uint) -> float {
|
||||
1.0/(((i+j)*(i+j+1u)/2u+i+1u) as float)
|
||||
#[inline]
|
||||
fn A(i: i32, j: i32) -> i32 {
|
||||
(i+j) * (i+j+1) / 2 + i + 1
|
||||
}
|
||||
|
||||
fn eval_A_times_u(u: &const [float], Au: &mut [float]) {
|
||||
let N = vec::len(u);
|
||||
let mut i = 0u;
|
||||
while i < N {
|
||||
Au[i] = 0.0;
|
||||
let mut j = 0u;
|
||||
while j < N {
|
||||
Au[i] += eval_A(i, j) * u[j];
|
||||
j += 1u;
|
||||
fn dot(v: &[f64], u: &[f64]) -> f64 {
|
||||
let mut sum = 0.0;
|
||||
for v.eachi |i, &v_i| {
|
||||
sum += v_i * u[i];
|
||||
}
|
||||
sum
|
||||
}
|
||||
|
||||
fn mult_Av(v: &mut [f64], out: &mut [f64]) {
|
||||
for vec::eachi_mut(out) |i, out_i| {
|
||||
let mut sum = 0.0;
|
||||
for vec::eachi_mut(v) |j, &v_j| {
|
||||
sum += v_j / (A(i as i32, j as i32) as f64);
|
||||
}
|
||||
i += 1u;
|
||||
*out_i = sum;
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_At_times_u(u: &const [float], Au: &mut [float]) {
|
||||
let N = vec::len(u);
|
||||
let mut i = 0u;
|
||||
while i < N {
|
||||
Au[i] = 0.0;
|
||||
let mut j = 0u;
|
||||
while j < N {
|
||||
Au[i] += eval_A(j, i) * u[j];
|
||||
j += 1u;
|
||||
fn mult_Atv(v: &mut [f64], out: &mut [f64]) {
|
||||
for vec::eachi_mut(out) |i, out_i| {
|
||||
let mut sum = 0.0;
|
||||
for vec::eachi_mut(v) |j, &v_j| {
|
||||
sum += v_j / (A(j as i32, i as i32) as f64);
|
||||
}
|
||||
i += 1u;
|
||||
*out_i = sum;
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_AtA_times_u(u: &const [float], AtAu: &mut [float]) {
|
||||
let mut v = vec::from_elem(vec::len(u), 0.0);
|
||||
eval_A_times_u(u, v);
|
||||
eval_At_times_u(v, AtAu);
|
||||
fn mult_AtAv(v: &mut [f64], out: &mut [f64], tmp: &mut [f64]) {
|
||||
mult_Av(v, tmp);
|
||||
mult_Atv(tmp, out);
|
||||
}
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
let args = if os::getenv(~"RUST_BENCH").is_some() {
|
||||
~[~"", ~"2000"]
|
||||
} else if args.len() <= 1u {
|
||||
~[~"", ~"1000"]
|
||||
} else {
|
||||
args
|
||||
};
|
||||
|
||||
let N = uint::from_str(args[1]).get();
|
||||
|
||||
let mut u = vec::from_elem(N, 1.0);
|
||||
let mut v = vec::from_elem(N, 0.0);
|
||||
let mut i = 0u;
|
||||
while i < 10u {
|
||||
eval_AtA_times_u(u, v);
|
||||
eval_AtA_times_u(v, u);
|
||||
i += 1u;
|
||||
let n: uint = FromStr::from_str(os::args()[1]).get();
|
||||
let mut u = vec::from_elem(n, 1f64), v = u.clone(), tmp = u.clone();
|
||||
for 8.times {
|
||||
mult_AtAv(u, v, tmp);
|
||||
mult_AtAv(v, u, tmp);
|
||||
}
|
||||
|
||||
let mut vBv = 0.0;
|
||||
let mut vv = 0.0;
|
||||
let mut i = 0u;
|
||||
while i < N {
|
||||
vBv += u[i] * v[i];
|
||||
vv += v[i] * v[i];
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
io::println(fmt!("%0.9f\n", float::sqrt(vBv / vv)));
|
||||
println(fmt!("%.9f", sqrtf64(dot(u,v) / dot(v,v)) as float));
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@ fn foo<T:Copy + Const>(x: T) -> T { x }
|
|||
struct F { field: int }
|
||||
|
||||
pub fn main() {
|
||||
foo(1);
|
||||
/*foo(1);
|
||||
foo(~"hi");
|
||||
foo(~[1, 2, 3]);
|
||||
foo(F{field: 42});
|
||||
foo((1, 2u));
|
||||
foo(@1);
|
||||
foo(@1);*/
|
||||
foo(~1);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
mod rustrt {
|
||||
pub extern {
|
||||
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
|
||||
-> libc::uintptr_t;
|
||||
-> libc::uintptr_t;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue