From 4d10bdc5b9fecee38abcad78a86e552a961b1a0a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 15 Feb 2014 23:49:08 -0800 Subject: std: Move intrinsics to std::intrinsics. Issue #1457 --- src/libstd/any.rs | 4 +- src/libstd/cast.rs | 2 +- src/libstd/intrinsics.rs | 459 ++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 3 +- src/libstd/local_data.rs | 2 +- src/libstd/mem.rs | 4 +- src/libstd/num/f32.rs | 2 +- src/libstd/num/f64.rs | 2 +- src/libstd/num/i16.rs | 2 +- src/libstd/num/i32.rs | 2 +- src/libstd/num/i64.rs | 2 +- src/libstd/num/i8.rs | 2 +- src/libstd/num/int.rs | 2 +- src/libstd/num/u16.rs | 2 +- src/libstd/num/u32.rs | 2 +- src/libstd/num/u64.rs | 2 +- src/libstd/num/u8.rs | 2 +- src/libstd/num/uint.rs | 2 +- src/libstd/ptr.rs | 2 +- src/libstd/reflect.rs | 2 +- src/libstd/repr.rs | 2 +- src/libstd/rt/global_heap.rs | 2 +- src/libstd/rt/unwind.rs | 2 +- src/libstd/rt/util.rs | 2 +- src/libstd/sync/atomics.rs | 2 +- src/libstd/unstable/intrinsics.rs | 457 ------------------------------------- src/libstd/unstable/mod.rs | 1 - src/libstd/unstable/stack.rs | 2 +- 28 files changed, 487 insertions(+), 485 deletions(-) create mode 100644 src/libstd/intrinsics.rs delete mode 100644 src/libstd/unstable/intrinsics.rs (limited to 'src/libstd') diff --git a/src/libstd/any.rs b/src/libstd/any.rs index 3f14db14882..06ae20d60bc 100644 --- a/src/libstd/any.rs +++ b/src/libstd/any.rs @@ -25,8 +25,8 @@ use fmt; use option::{Option, Some, None}; use result::{Result, Ok, Err}; use to_str::ToStr; -use unstable::intrinsics::TypeId; -use unstable::intrinsics; +use intrinsics::TypeId; +use intrinsics; /// A type with no inhabitants pub enum Void { } diff --git a/src/libstd/cast.rs b/src/libstd/cast.rs index ffdd70a6c14..c2db0c78205 100644 --- a/src/libstd/cast.rs +++ b/src/libstd/cast.rs @@ -11,7 +11,7 @@ //! Unsafe casting functions use mem; -use unstable::intrinsics; +use intrinsics; use ptr::copy_nonoverlapping_memory; /// Casts the value at `src` to U. The two types must have the same length. diff --git a/src/libstd/intrinsics.rs b/src/libstd/intrinsics.rs new file mode 100644 index 00000000000..b386335a428 --- /dev/null +++ b/src/libstd/intrinsics.rs @@ -0,0 +1,459 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! rustc compiler intrinsics. + +The corresponding definitions are in librustc/middle/trans/foreign.rs. + +# Volatiles + +The volatile intrinsics provide operations intended to act on I/O +memory, which are guaranteed to not be reordered by the compiler +across other volatile intrinsics. See the LLVM documentation on +[[volatile]]. + +[volatile]: http://llvm.org/docs/LangRef.html#volatile-memory-accesses + +# Atomics + +The atomic intrinsics provide common atomic operations on machine +words, with multiple possible memory orderings. They obey the same +semantics as C++11. See the LLVM documentation on [[atomics]]. + +[atomics]: http://llvm.org/docs/Atomics.html + +A quick refresher on memory ordering: + +* Acquire - a barrier for acquiring a lock. Subsequent reads and writes + take place after the barrier. +* Release - a barrier for releasing a lock. Preceding reads and writes + take place before the barrier. +* Sequentially consistent - sequentially consistent operations are + guaranteed to happen in order. This is the standard mode for working + with atomic types and is equivalent to Java's `volatile`. + +*/ + +#[allow(missing_doc)]; + +// This is needed to prevent duplicate lang item definitions. +#[cfg(test)] +pub use realstd::intrinsics::{TyDesc, Opaque, TyVisitor, TypeId}; + +pub type GlueFn = extern "Rust" fn(*i8); + +#[lang="ty_desc"] +#[cfg(not(test))] +pub struct TyDesc { + // sizeof(T) + size: uint, + + // alignof(T) + align: uint, + + // Called when a value of type `T` is no longer needed + drop_glue: GlueFn, + + // Called by reflection visitor to visit a value of type `T` + visit_glue: GlueFn, + + // Name corresponding to the type + name: &'static str +} + +#[lang="opaque"] +#[cfg(not(test))] +pub enum Opaque { } + +pub type Disr = u64; + +#[lang="ty_visitor"] +#[cfg(not(test))] +pub trait TyVisitor { + fn visit_bot(&mut self) -> bool; + fn visit_nil(&mut self) -> bool; + fn visit_bool(&mut self) -> bool; + + fn visit_int(&mut self) -> bool; + fn visit_i8(&mut self) -> bool; + fn visit_i16(&mut self) -> bool; + fn visit_i32(&mut self) -> bool; + fn visit_i64(&mut self) -> bool; + + fn visit_uint(&mut self) -> bool; + fn visit_u8(&mut self) -> bool; + fn visit_u16(&mut self) -> bool; + fn visit_u32(&mut self) -> bool; + fn visit_u64(&mut self) -> bool; + + fn visit_f32(&mut self) -> bool; + fn visit_f64(&mut self) -> bool; + + fn visit_char(&mut self) -> bool; + + fn visit_estr_box(&mut self) -> bool; + fn visit_estr_uniq(&mut self) -> bool; + fn visit_estr_slice(&mut self) -> bool; + fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool; + + fn visit_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_ptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool; + + fn visit_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, + mtbl: uint, inner: *TyDesc) -> bool; + + fn visit_enter_rec(&mut self, n_fields: uint, + sz: uint, align: uint) -> bool; + fn visit_rec_field(&mut self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool; + fn visit_leave_rec(&mut self, n_fields: uint, + sz: uint, align: uint) -> bool; + + fn visit_enter_class(&mut self, name: &str, named_fields: bool, n_fields: uint, + sz: uint, align: uint) -> bool; + fn visit_class_field(&mut self, i: uint, name: &str, named: bool, + mtbl: uint, inner: *TyDesc) -> bool; + fn visit_leave_class(&mut self, name: &str, named_fields: bool, n_fields: uint, + sz: uint, align: uint) -> bool; + + fn visit_enter_tup(&mut self, n_fields: uint, + sz: uint, align: uint) -> bool; + fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool; + fn visit_leave_tup(&mut self, n_fields: uint, + sz: uint, align: uint) -> bool; + + fn visit_enter_enum(&mut self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> Disr, + sz: uint, align: uint) -> bool; + fn visit_enter_enum_variant(&mut self, variant: uint, + disr_val: Disr, + n_fields: uint, + name: &str) -> bool; + fn visit_enum_variant_field(&mut self, i: uint, offset: uint, inner: *TyDesc) -> bool; + fn visit_leave_enum_variant(&mut self, variant: uint, + disr_val: Disr, + n_fields: uint, + name: &str) -> bool; + fn visit_leave_enum(&mut self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> Disr, + sz: uint, align: uint) -> bool; + + fn visit_enter_fn(&mut self, purity: uint, proto: uint, + n_inputs: uint, retstyle: uint) -> bool; + fn visit_fn_input(&mut self, i: uint, mode: uint, inner: *TyDesc) -> bool; + fn visit_fn_output(&mut self, retstyle: uint, variadic: bool, inner: *TyDesc) -> bool; + fn visit_leave_fn(&mut self, purity: uint, proto: uint, + n_inputs: uint, retstyle: uint) -> bool; + + fn visit_trait(&mut self, name: &str) -> bool; + fn visit_param(&mut self, i: uint) -> bool; + fn visit_self(&mut self) -> bool; +} + +extern "rust-intrinsic" { + pub fn atomic_cxchg(dst: &mut T, old: T, src: T) -> T; + pub fn atomic_cxchg_acq(dst: &mut T, old: T, src: T) -> T; + pub fn atomic_cxchg_rel(dst: &mut T, old: T, src: T) -> T; + pub fn atomic_cxchg_acqrel(dst: &mut T, old: T, src: T) -> T; + pub fn atomic_cxchg_relaxed(dst: &mut T, old: T, src: T) -> T; + + pub fn atomic_load(src: &T) -> T; + pub fn atomic_load_acq(src: &T) -> T; + pub fn atomic_load_relaxed(src: &T) -> T; + + pub fn atomic_store(dst: &mut T, val: T); + pub fn atomic_store_rel(dst: &mut T, val: T); + pub fn atomic_store_relaxed(dst: &mut T, val: T); + + pub fn atomic_xchg(dst: &mut T, src: T) -> T; + pub fn atomic_xchg_acq(dst: &mut T, src: T) -> T; + pub fn atomic_xchg_rel(dst: &mut T, src: T) -> T; + pub fn atomic_xchg_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_xchg_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_xadd(dst: &mut T, src: T) -> T; + pub fn atomic_xadd_acq(dst: &mut T, src: T) -> T; + pub fn atomic_xadd_rel(dst: &mut T, src: T) -> T; + pub fn atomic_xadd_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_xadd_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_xsub(dst: &mut T, src: T) -> T; + pub fn atomic_xsub_acq(dst: &mut T, src: T) -> T; + pub fn atomic_xsub_rel(dst: &mut T, src: T) -> T; + pub fn atomic_xsub_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_xsub_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_and(dst: &mut T, src: T) -> T; + pub fn atomic_and_acq(dst: &mut T, src: T) -> T; + pub fn atomic_and_rel(dst: &mut T, src: T) -> T; + pub fn atomic_and_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_and_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_nand(dst: &mut T, src: T) -> T; + pub fn atomic_nand_acq(dst: &mut T, src: T) -> T; + pub fn atomic_nand_rel(dst: &mut T, src: T) -> T; + pub fn atomic_nand_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_nand_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_or(dst: &mut T, src: T) -> T; + pub fn atomic_or_acq(dst: &mut T, src: T) -> T; + pub fn atomic_or_rel(dst: &mut T, src: T) -> T; + pub fn atomic_or_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_or_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_xor(dst: &mut T, src: T) -> T; + pub fn atomic_xor_acq(dst: &mut T, src: T) -> T; + pub fn atomic_xor_rel(dst: &mut T, src: T) -> T; + pub fn atomic_xor_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_xor_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_max(dst: &mut T, src: T) -> T; + pub fn atomic_max_acq(dst: &mut T, src: T) -> T; + pub fn atomic_max_rel(dst: &mut T, src: T) -> T; + pub fn atomic_max_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_max_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_min(dst: &mut T, src: T) -> T; + pub fn atomic_min_acq(dst: &mut T, src: T) -> T; + pub fn atomic_min_rel(dst: &mut T, src: T) -> T; + pub fn atomic_min_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_min_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_umin(dst: &mut T, src: T) -> T; + pub fn atomic_umin_acq(dst: &mut T, src: T) -> T; + pub fn atomic_umin_rel(dst: &mut T, src: T) -> T; + pub fn atomic_umin_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_umin_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_umax(dst: &mut T, src: T) -> T; + pub fn atomic_umax_acq(dst: &mut T, src: T) -> T; + pub fn atomic_umax_rel(dst: &mut T, src: T) -> T; + pub fn atomic_umax_acqrel(dst: &mut T, src: T) -> T; + pub fn atomic_umax_relaxed(dst: &mut T, src: T) -> T; + + pub fn atomic_fence(); + pub fn atomic_fence_acq(); + pub fn atomic_fence_rel(); + pub fn atomic_fence_acqrel(); + + /// Abort the execution of the process. + pub fn abort() -> !; + + /// Execute a breakpoint trap, for inspection by a debugger. + pub fn breakpoint(); + + pub fn volatile_load(src: *T) -> T; + pub fn volatile_store(dst: *mut T, val: T); + + + /// The size of a type in bytes. + /// + /// This is the exact number of bytes in memory taken up by a + /// value of the given type. In other words, a memset of this size + /// would *exactly* overwrite a value. When laid out in vectors + /// and structures there may be additional padding between + /// elements. + pub fn size_of() -> uint; + + /// Move a value to an uninitialized memory location. + /// + /// Drop glue is not run on the destination. + pub fn move_val_init(dst: &mut T, src: T); + + pub fn min_align_of() -> uint; + pub fn pref_align_of() -> uint; + + /// Get a static pointer to a type descriptor. + pub fn get_tydesc() -> *TyDesc; + + /// Gets an identifier which is globally unique to the specified type. This + /// function will return the same value for a type regardless of whichever + /// crate it is invoked in. + pub fn type_id() -> TypeId; + + + /// Create a value initialized to zero. + /// + /// `init` is unsafe because it returns a zeroed-out datum, + /// which is unsafe unless T is Pod. + pub fn init() -> T; + + /// Create an uninitialized value. + pub fn uninit() -> T; + + /// Move a value out of scope without running drop glue. + /// + /// `forget` is unsafe because the caller is responsible for + /// ensuring the argument is deallocated already. + pub fn forget(_: T) -> (); + pub fn transmute(e: T) -> U; + + /// Returns `true` if a type requires drop glue. + pub fn needs_drop() -> bool; + + /// Returns `true` if a type is managed (will be allocated on the local heap) + pub fn owns_managed() -> bool; + + pub fn visit_tydesc(td: *TyDesc, tv: &mut TyVisitor); + + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. An arithmetic overflow is also + /// undefined behaviour. + /// + /// This is implemented as an intrinsic to avoid converting to and from an + /// integer, since the conversion would throw away aliasing information. + pub fn offset(dst: *T, offset: int) -> *T; + + /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with + /// a size of `count` * `size_of::()` and an alignment of + /// `min_align_of::()` + pub fn copy_nonoverlapping_memory(dst: *mut T, src: *T, count: uint); + + /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with + /// a size of `count` * `size_of::()` and an alignment of + /// `min_align_of::()` + pub fn copy_memory(dst: *mut T, src: *T, count: uint); + + /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a + /// size of `count` * `size_of::()` and an alignment of + /// `min_align_of::()` + pub fn set_memory(dst: *mut T, val: u8, count: uint); + + pub fn sqrtf32(x: f32) -> f32; + pub fn sqrtf64(x: f64) -> f64; + + pub fn powif32(a: f32, x: i32) -> f32; + pub fn powif64(a: f64, x: i32) -> f64; + + pub fn sinf32(x: f32) -> f32; + pub fn sinf64(x: f64) -> f64; + + pub fn cosf32(x: f32) -> f32; + pub fn cosf64(x: f64) -> f64; + + pub fn powf32(a: f32, x: f32) -> f32; + pub fn powf64(a: f64, x: f64) -> f64; + + pub fn expf32(x: f32) -> f32; + pub fn expf64(x: f64) -> f64; + + pub fn exp2f32(x: f32) -> f32; + pub fn exp2f64(x: f64) -> f64; + + pub fn logf32(x: f32) -> f32; + pub fn logf64(x: f64) -> f64; + + pub fn log10f32(x: f32) -> f32; + pub fn log10f64(x: f64) -> f64; + + pub fn log2f32(x: f32) -> f32; + pub fn log2f64(x: f64) -> f64; + + pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; + pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; + + pub fn fabsf32(x: f32) -> f32; + pub fn fabsf64(x: f64) -> f64; + + pub fn copysignf32(x: f32, y: f32) -> f32; + pub fn copysignf64(x: f64, y: f64) -> f64; + + pub fn floorf32(x: f32) -> f32; + pub fn floorf64(x: f64) -> f64; + + pub fn ceilf32(x: f32) -> f32; + pub fn ceilf64(x: f64) -> f64; + + pub fn truncf32(x: f32) -> f32; + pub fn truncf64(x: f64) -> f64; + + pub fn rintf32(x: f32) -> f32; + pub fn rintf64(x: f64) -> f64; + + pub fn nearbyintf32(x: f32) -> f32; + pub fn nearbyintf64(x: f64) -> f64; + + pub fn roundf32(x: f32) -> f32; + pub fn roundf64(x: f64) -> f64; + + pub fn ctpop8(x: i8) -> i8; + pub fn ctpop16(x: i16) -> i16; + pub fn ctpop32(x: i32) -> i32; + pub fn ctpop64(x: i64) -> i64; + + pub fn ctlz8(x: i8) -> i8; + pub fn ctlz16(x: i16) -> i16; + pub fn ctlz32(x: i32) -> i32; + pub fn ctlz64(x: i64) -> i64; + + pub fn cttz8(x: i8) -> i8; + pub fn cttz16(x: i16) -> i16; + pub fn cttz32(x: i32) -> i32; + pub fn cttz64(x: i64) -> i64; + + pub fn bswap16(x: i16) -> i16; + pub fn bswap32(x: i32) -> i32; + pub fn bswap64(x: i64) -> i64; + + pub fn i8_add_with_overflow(x: i8, y: i8) -> (i8, bool); + pub fn i16_add_with_overflow(x: i16, y: i16) -> (i16, bool); + pub fn i32_add_with_overflow(x: i32, y: i32) -> (i32, bool); + pub fn i64_add_with_overflow(x: i64, y: i64) -> (i64, bool); + + pub fn u8_add_with_overflow(x: u8, y: u8) -> (u8, bool); + pub fn u16_add_with_overflow(x: u16, y: u16) -> (u16, bool); + pub fn u32_add_with_overflow(x: u32, y: u32) -> (u32, bool); + pub fn u64_add_with_overflow(x: u64, y: u64) -> (u64, bool); + + pub fn i8_sub_with_overflow(x: i8, y: i8) -> (i8, bool); + pub fn i16_sub_with_overflow(x: i16, y: i16) -> (i16, bool); + pub fn i32_sub_with_overflow(x: i32, y: i32) -> (i32, bool); + pub fn i64_sub_with_overflow(x: i64, y: i64) -> (i64, bool); + + pub fn u8_sub_with_overflow(x: u8, y: u8) -> (u8, bool); + pub fn u16_sub_with_overflow(x: u16, y: u16) -> (u16, bool); + pub fn u32_sub_with_overflow(x: u32, y: u32) -> (u32, bool); + pub fn u64_sub_with_overflow(x: u64, y: u64) -> (u64, bool); + + pub fn i8_mul_with_overflow(x: i8, y: i8) -> (i8, bool); + pub fn i16_mul_with_overflow(x: i16, y: i16) -> (i16, bool); + pub fn i32_mul_with_overflow(x: i32, y: i32) -> (i32, bool); + pub fn i64_mul_with_overflow(x: i64, y: i64) -> (i64, bool); + + pub fn u8_mul_with_overflow(x: u8, y: u8) -> (u8, bool); + pub fn u16_mul_with_overflow(x: u16, y: u16) -> (u16, bool); + pub fn u32_mul_with_overflow(x: u32, y: u32) -> (u32, bool); + pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool); +} + + +/// `TypeId` represents a globally unique identifier for a type +#[lang="type_id"] // This needs to be kept in lockstep with the code in trans/intrinsic.rs and + // middle/lang_items.rs +#[deriving(Eq, IterBytes)] +#[cfg(not(test))] +pub struct TypeId { + priv t: u64, +} + +#[cfg(not(test))] +impl TypeId { + /// Returns the `TypeId` of the type this generic function has been instantiated with + pub fn of() -> TypeId { + unsafe { type_id::() } + } +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 6996cba42b4..46958974484 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -196,7 +196,8 @@ pub mod reflect; // Private APIs #[unstable] pub mod unstable; - +#[experimental] +pub mod intrinsics; /* For internal use, not exported */ diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index 043da46ba5e..6b854daabda 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -281,7 +281,7 @@ fn get_with ! { - use std::unstable::intrinsics; + use intrinsics; unsafe { intrinsics::abort() } } diff --git a/src/libstd/mem.rs b/src/libstd/mem.rs index 11053f01ded..603f2b80eea 100644 --- a/src/libstd/mem.rs +++ b/src/libstd/mem.rs @@ -17,8 +17,8 @@ use cast; use ptr; -use unstable::intrinsics; -use unstable::intrinsics::{bswap16, bswap32, bswap64}; +use intrinsics; +use intrinsics::{bswap16, bswap32, bswap64}; /// Returns the size of a type in bytes. #[inline] diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index da3f2c1636f..7b1fe949199 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -20,7 +20,7 @@ use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; use num::{Zero, One, Bounded, strconv}; use num; use to_str; -use unstable::intrinsics; +use intrinsics; macro_rules! delegate( ( diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 24165cbef50..d5a571cdd23 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -21,7 +21,7 @@ use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; use num::{Zero, One, Bounded, strconv}; use num; use to_str; -use unstable::intrinsics; +use intrinsics; pub use cmp::{min, max}; diff --git a/src/libstd/num/i16.rs b/src/libstd/num/i16.rs index cbeff5d4aa2..141626ed98a 100644 --- a/src/libstd/num/i16.rs +++ b/src/libstd/num/i16.rs @@ -20,7 +20,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; int_module!(i16, 16) diff --git a/src/libstd/num/i32.rs b/src/libstd/num/i32.rs index 9afc1a14545..a43a6e6a288 100644 --- a/src/libstd/num/i32.rs +++ b/src/libstd/num/i32.rs @@ -20,7 +20,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; int_module!(i32, 32) diff --git a/src/libstd/num/i64.rs b/src/libstd/num/i64.rs index f1e9f5a4fdc..e8503d808a7 100644 --- a/src/libstd/num/i64.rs +++ b/src/libstd/num/i64.rs @@ -22,7 +22,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; int_module!(i64, 64) diff --git a/src/libstd/num/i8.rs b/src/libstd/num/i8.rs index e0e549b731a..9f857ff40ff 100644 --- a/src/libstd/num/i8.rs +++ b/src/libstd/num/i8.rs @@ -20,7 +20,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; int_module!(i8, 8) diff --git a/src/libstd/num/int.rs b/src/libstd/num/int.rs index d525639045e..6d1a50b724f 100644 --- a/src/libstd/num/int.rs +++ b/src/libstd/num/int.rs @@ -20,7 +20,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; #[cfg(target_word_size = "32")] int_module!(int, 32) #[cfg(target_word_size = "64")] int_module!(int, 64) diff --git a/src/libstd/num/u16.rs b/src/libstd/num/u16.rs index 770db889af5..da0293b3418 100644 --- a/src/libstd/num/u16.rs +++ b/src/libstd/num/u16.rs @@ -21,7 +21,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; uint_module!(u16, i16, 16) diff --git a/src/libstd/num/u32.rs b/src/libstd/num/u32.rs index 9e08ffed3b7..b103e18f701 100644 --- a/src/libstd/num/u32.rs +++ b/src/libstd/num/u32.rs @@ -21,7 +21,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; uint_module!(u32, i32, 32) diff --git a/src/libstd/num/u64.rs b/src/libstd/num/u64.rs index 17eebed967c..f7956f0128e 100644 --- a/src/libstd/num/u64.rs +++ b/src/libstd/num/u64.rs @@ -23,7 +23,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; uint_module!(u64, i64, 64) diff --git a/src/libstd/num/u8.rs b/src/libstd/num/u8.rs index 4aa34b6d880..e6ce9c72e96 100644 --- a/src/libstd/num/u8.rs +++ b/src/libstd/num/u8.rs @@ -21,7 +21,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; uint_module!(u8, i8, 8) diff --git a/src/libstd/num/uint.rs b/src/libstd/num/uint.rs index 1811ebc7acc..a8c85787f7e 100644 --- a/src/libstd/num/uint.rs +++ b/src/libstd/num/uint.rs @@ -21,7 +21,7 @@ use num::{CheckedDiv, Zero, One, strconv}; use num::{ToStrRadix, FromStrRadix}; use option::{Option, Some, None}; use str; -use unstable::intrinsics; +use intrinsics; uint_module!(uint, int, ::int::BITS) diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index 193e9ea7052..86264c1ca55 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -17,7 +17,7 @@ use cmp::Equiv; use iter::{range, Iterator}; use mem; use option::{Option, Some, None}; -use unstable::intrinsics; +use intrinsics; #[cfg(not(test))] use cmp::{Eq, Ord}; diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index f88da60ae9b..5ee840748e6 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -16,7 +16,7 @@ Runtime type reflection #[allow(missing_doc)]; -use unstable::intrinsics::{Disr, Opaque, TyDesc, TyVisitor}; +use intrinsics::{Disr, Opaque, TyDesc, TyVisitor}; use mem; use unstable::raw; diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index 680ac112300..8e1a0714748 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -29,7 +29,7 @@ use result::{Ok, Err}; use str::StrSlice; use to_str::ToStr; use vec::OwnedVector; -use unstable::intrinsics::{Disr, Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc}; +use intrinsics::{Disr, Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc}; use unstable::raw; macro_rules! try( ($me:expr, $e:expr) => ( diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 8128bb02148..191d57a58fc 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -10,7 +10,7 @@ use libc::{c_void, size_t, free, malloc, realloc}; use ptr::{RawPtr, mut_null}; -use unstable::intrinsics::abort; +use intrinsics::abort; use unstable::raw; use mem::size_of; diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index ef8bd94c897..127859b4275 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -69,7 +69,7 @@ use rt::local::Local; use rt::task::Task; use str::Str; use task::TaskResult; -use unstable::intrinsics; +use intrinsics; use uw = self::libunwind; diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 69e240f30bc..408f51f2017 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -143,7 +143,7 @@ memory and partly incapable of presentation to others.", abort(); fn abort() -> ! { - use std::unstable::intrinsics; + use intrinsics; unsafe { intrinsics::abort() } } } diff --git a/src/libstd/sync/atomics.rs b/src/libstd/sync/atomics.rs index 00ce07d747f..b4d465c0397 100644 --- a/src/libstd/sync/atomics.rs +++ b/src/libstd/sync/atomics.rs @@ -21,7 +21,7 @@ #[allow(missing_doc)]; -use unstable::intrinsics; +use intrinsics; use cast; use std::kinds::marker; use option::{Option,Some,None}; diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs deleted file mode 100644 index c983d82563c..00000000000 --- a/src/libstd/unstable/intrinsics.rs +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! rustc compiler intrinsics. - -The corresponding definitions are in librustc/middle/trans/foreign.rs. - -# Volatiles - -The volatile intrinsics provide operations intended to act on I/O -memory, which are guaranteed to not be reordered by the compiler -across other volatile intrinsics. See the LLVM documentation on -[[volatile]]. - -[volatile]: http://llvm.org/docs/LangRef.html#volatile-memory-accesses - -# Atomics - -The atomic intrinsics provide common atomic operations on machine -words, with multiple possible memory orderings. They obey the same -semantics as C++11. See the LLVM documentation on [[atomics]]. - -[atomics]: http://llvm.org/docs/Atomics.html - -A quick refresher on memory ordering: - -* Acquire - a barrier for acquiring a lock. Subsequent reads and writes - take place after the barrier. -* Release - a barrier for releasing a lock. Preceding reads and writes - take place before the barrier. -* Sequentially consistent - sequentially consistent operations are - guaranteed to happen in order. This is the standard mode for working - with atomic types and is equivalent to Java's `volatile`. - -*/ - -// This is needed to prevent duplicate lang item definitions. -#[cfg(test)] -pub use realstd::unstable::intrinsics::{TyDesc, Opaque, TyVisitor, TypeId}; - -pub type GlueFn = extern "Rust" fn(*i8); - -#[lang="ty_desc"] -#[cfg(not(test))] -pub struct TyDesc { - // sizeof(T) - size: uint, - - // alignof(T) - align: uint, - - // Called when a value of type `T` is no longer needed - drop_glue: GlueFn, - - // Called by reflection visitor to visit a value of type `T` - visit_glue: GlueFn, - - // Name corresponding to the type - name: &'static str -} - -#[lang="opaque"] -#[cfg(not(test))] -pub enum Opaque { } - -pub type Disr = u64; - -#[lang="ty_visitor"] -#[cfg(not(test))] -pub trait TyVisitor { - fn visit_bot(&mut self) -> bool; - fn visit_nil(&mut self) -> bool; - fn visit_bool(&mut self) -> bool; - - fn visit_int(&mut self) -> bool; - fn visit_i8(&mut self) -> bool; - fn visit_i16(&mut self) -> bool; - fn visit_i32(&mut self) -> bool; - fn visit_i64(&mut self) -> bool; - - fn visit_uint(&mut self) -> bool; - fn visit_u8(&mut self) -> bool; - fn visit_u16(&mut self) -> bool; - fn visit_u32(&mut self) -> bool; - fn visit_u64(&mut self) -> bool; - - fn visit_f32(&mut self) -> bool; - fn visit_f64(&mut self) -> bool; - - fn visit_char(&mut self) -> bool; - - fn visit_estr_box(&mut self) -> bool; - fn visit_estr_uniq(&mut self) -> bool; - fn visit_estr_slice(&mut self) -> bool; - fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool; - - fn visit_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_ptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool; - - fn visit_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, - mtbl: uint, inner: *TyDesc) -> bool; - - fn visit_enter_rec(&mut self, n_fields: uint, - sz: uint, align: uint) -> bool; - fn visit_rec_field(&mut self, i: uint, name: &str, - mtbl: uint, inner: *TyDesc) -> bool; - fn visit_leave_rec(&mut self, n_fields: uint, - sz: uint, align: uint) -> bool; - - fn visit_enter_class(&mut self, name: &str, named_fields: bool, n_fields: uint, - sz: uint, align: uint) -> bool; - fn visit_class_field(&mut self, i: uint, name: &str, named: bool, - mtbl: uint, inner: *TyDesc) -> bool; - fn visit_leave_class(&mut self, name: &str, named_fields: bool, n_fields: uint, - sz: uint, align: uint) -> bool; - - fn visit_enter_tup(&mut self, n_fields: uint, - sz: uint, align: uint) -> bool; - fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool; - fn visit_leave_tup(&mut self, n_fields: uint, - sz: uint, align: uint) -> bool; - - fn visit_enter_enum(&mut self, n_variants: uint, - get_disr: extern unsafe fn(ptr: *Opaque) -> Disr, - sz: uint, align: uint) -> bool; - fn visit_enter_enum_variant(&mut self, variant: uint, - disr_val: Disr, - n_fields: uint, - name: &str) -> bool; - fn visit_enum_variant_field(&mut self, i: uint, offset: uint, inner: *TyDesc) -> bool; - fn visit_leave_enum_variant(&mut self, variant: uint, - disr_val: Disr, - n_fields: uint, - name: &str) -> bool; - fn visit_leave_enum(&mut self, n_variants: uint, - get_disr: extern unsafe fn(ptr: *Opaque) -> Disr, - sz: uint, align: uint) -> bool; - - fn visit_enter_fn(&mut self, purity: uint, proto: uint, - n_inputs: uint, retstyle: uint) -> bool; - fn visit_fn_input(&mut self, i: uint, mode: uint, inner: *TyDesc) -> bool; - fn visit_fn_output(&mut self, retstyle: uint, variadic: bool, inner: *TyDesc) -> bool; - fn visit_leave_fn(&mut self, purity: uint, proto: uint, - n_inputs: uint, retstyle: uint) -> bool; - - fn visit_trait(&mut self, name: &str) -> bool; - fn visit_param(&mut self, i: uint) -> bool; - fn visit_self(&mut self) -> bool; -} - -extern "rust-intrinsic" { - pub fn atomic_cxchg(dst: &mut T, old: T, src: T) -> T; - pub fn atomic_cxchg_acq(dst: &mut T, old: T, src: T) -> T; - pub fn atomic_cxchg_rel(dst: &mut T, old: T, src: T) -> T; - pub fn atomic_cxchg_acqrel(dst: &mut T, old: T, src: T) -> T; - pub fn atomic_cxchg_relaxed(dst: &mut T, old: T, src: T) -> T; - - pub fn atomic_load(src: &T) -> T; - pub fn atomic_load_acq(src: &T) -> T; - pub fn atomic_load_relaxed(src: &T) -> T; - - pub fn atomic_store(dst: &mut T, val: T); - pub fn atomic_store_rel(dst: &mut T, val: T); - pub fn atomic_store_relaxed(dst: &mut T, val: T); - - pub fn atomic_xchg(dst: &mut T, src: T) -> T; - pub fn atomic_xchg_acq(dst: &mut T, src: T) -> T; - pub fn atomic_xchg_rel(dst: &mut T, src: T) -> T; - pub fn atomic_xchg_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_xchg_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_xadd(dst: &mut T, src: T) -> T; - pub fn atomic_xadd_acq(dst: &mut T, src: T) -> T; - pub fn atomic_xadd_rel(dst: &mut T, src: T) -> T; - pub fn atomic_xadd_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_xadd_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_xsub(dst: &mut T, src: T) -> T; - pub fn atomic_xsub_acq(dst: &mut T, src: T) -> T; - pub fn atomic_xsub_rel(dst: &mut T, src: T) -> T; - pub fn atomic_xsub_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_xsub_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_and(dst: &mut T, src: T) -> T; - pub fn atomic_and_acq(dst: &mut T, src: T) -> T; - pub fn atomic_and_rel(dst: &mut T, src: T) -> T; - pub fn atomic_and_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_and_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_nand(dst: &mut T, src: T) -> T; - pub fn atomic_nand_acq(dst: &mut T, src: T) -> T; - pub fn atomic_nand_rel(dst: &mut T, src: T) -> T; - pub fn atomic_nand_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_nand_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_or(dst: &mut T, src: T) -> T; - pub fn atomic_or_acq(dst: &mut T, src: T) -> T; - pub fn atomic_or_rel(dst: &mut T, src: T) -> T; - pub fn atomic_or_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_or_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_xor(dst: &mut T, src: T) -> T; - pub fn atomic_xor_acq(dst: &mut T, src: T) -> T; - pub fn atomic_xor_rel(dst: &mut T, src: T) -> T; - pub fn atomic_xor_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_xor_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_max(dst: &mut T, src: T) -> T; - pub fn atomic_max_acq(dst: &mut T, src: T) -> T; - pub fn atomic_max_rel(dst: &mut T, src: T) -> T; - pub fn atomic_max_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_max_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_min(dst: &mut T, src: T) -> T; - pub fn atomic_min_acq(dst: &mut T, src: T) -> T; - pub fn atomic_min_rel(dst: &mut T, src: T) -> T; - pub fn atomic_min_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_min_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_umin(dst: &mut T, src: T) -> T; - pub fn atomic_umin_acq(dst: &mut T, src: T) -> T; - pub fn atomic_umin_rel(dst: &mut T, src: T) -> T; - pub fn atomic_umin_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_umin_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_umax(dst: &mut T, src: T) -> T; - pub fn atomic_umax_acq(dst: &mut T, src: T) -> T; - pub fn atomic_umax_rel(dst: &mut T, src: T) -> T; - pub fn atomic_umax_acqrel(dst: &mut T, src: T) -> T; - pub fn atomic_umax_relaxed(dst: &mut T, src: T) -> T; - - pub fn atomic_fence(); - pub fn atomic_fence_acq(); - pub fn atomic_fence_rel(); - pub fn atomic_fence_acqrel(); - - /// Abort the execution of the process. - pub fn abort() -> !; - - /// Execute a breakpoint trap, for inspection by a debugger. - pub fn breakpoint(); - - pub fn volatile_load(src: *T) -> T; - pub fn volatile_store(dst: *mut T, val: T); - - - /// The size of a type in bytes. - /// - /// This is the exact number of bytes in memory taken up by a - /// value of the given type. In other words, a memset of this size - /// would *exactly* overwrite a value. When laid out in vectors - /// and structures there may be additional padding between - /// elements. - pub fn size_of() -> uint; - - /// Move a value to an uninitialized memory location. - /// - /// Drop glue is not run on the destination. - pub fn move_val_init(dst: &mut T, src: T); - - pub fn min_align_of() -> uint; - pub fn pref_align_of() -> uint; - - /// Get a static pointer to a type descriptor. - pub fn get_tydesc() -> *TyDesc; - - /// Gets an identifier which is globally unique to the specified type. This - /// function will return the same value for a type regardless of whichever - /// crate it is invoked in. - pub fn type_id() -> TypeId; - - - /// Create a value initialized to zero. - /// - /// `init` is unsafe because it returns a zeroed-out datum, - /// which is unsafe unless T is Pod. - pub fn init() -> T; - - /// Create an uninitialized value. - pub fn uninit() -> T; - - /// Move a value out of scope without running drop glue. - /// - /// `forget` is unsafe because the caller is responsible for - /// ensuring the argument is deallocated already. - pub fn forget(_: T) -> (); - pub fn transmute(e: T) -> U; - - /// Returns `true` if a type requires drop glue. - pub fn needs_drop() -> bool; - - /// Returns `true` if a type is managed (will be allocated on the local heap) - pub fn owns_managed() -> bool; - - pub fn visit_tydesc(td: *TyDesc, tv: &mut TyVisitor); - - /// Calculates the offset from a pointer. The offset *must* be in-bounds of - /// the object, or one-byte-past-the-end. An arithmetic overflow is also - /// undefined behaviour. - /// - /// This is implemented as an intrinsic to avoid converting to and from an - /// integer, since the conversion would throw away aliasing information. - pub fn offset(dst: *T, offset: int) -> *T; - - /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with - /// a size of `count` * `size_of::()` and an alignment of - /// `min_align_of::()` - pub fn copy_nonoverlapping_memory(dst: *mut T, src: *T, count: uint); - - /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with - /// a size of `count` * `size_of::()` and an alignment of - /// `min_align_of::()` - pub fn copy_memory(dst: *mut T, src: *T, count: uint); - - /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a - /// size of `count` * `size_of::()` and an alignment of - /// `min_align_of::()` - pub fn set_memory(dst: *mut T, val: u8, count: uint); - - pub fn sqrtf32(x: f32) -> f32; - pub fn sqrtf64(x: f64) -> f64; - - pub fn powif32(a: f32, x: i32) -> f32; - pub fn powif64(a: f64, x: i32) -> f64; - - pub fn sinf32(x: f32) -> f32; - pub fn sinf64(x: f64) -> f64; - - pub fn cosf32(x: f32) -> f32; - pub fn cosf64(x: f64) -> f64; - - pub fn powf32(a: f32, x: f32) -> f32; - pub fn powf64(a: f64, x: f64) -> f64; - - pub fn expf32(x: f32) -> f32; - pub fn expf64(x: f64) -> f64; - - pub fn exp2f32(x: f32) -> f32; - pub fn exp2f64(x: f64) -> f64; - - pub fn logf32(x: f32) -> f32; - pub fn logf64(x: f64) -> f64; - - pub fn log10f32(x: f32) -> f32; - pub fn log10f64(x: f64) -> f64; - - pub fn log2f32(x: f32) -> f32; - pub fn log2f64(x: f64) -> f64; - - pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; - pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; - - pub fn fabsf32(x: f32) -> f32; - pub fn fabsf64(x: f64) -> f64; - - pub fn copysignf32(x: f32, y: f32) -> f32; - pub fn copysignf64(x: f64, y: f64) -> f64; - - pub fn floorf32(x: f32) -> f32; - pub fn floorf64(x: f64) -> f64; - - pub fn ceilf32(x: f32) -> f32; - pub fn ceilf64(x: f64) -> f64; - - pub fn truncf32(x: f32) -> f32; - pub fn truncf64(x: f64) -> f64; - - pub fn rintf32(x: f32) -> f32; - pub fn rintf64(x: f64) -> f64; - - pub fn nearbyintf32(x: f32) -> f32; - pub fn nearbyintf64(x: f64) -> f64; - - pub fn roundf32(x: f32) -> f32; - pub fn roundf64(x: f64) -> f64; - - pub fn ctpop8(x: i8) -> i8; - pub fn ctpop16(x: i16) -> i16; - pub fn ctpop32(x: i32) -> i32; - pub fn ctpop64(x: i64) -> i64; - - pub fn ctlz8(x: i8) -> i8; - pub fn ctlz16(x: i16) -> i16; - pub fn ctlz32(x: i32) -> i32; - pub fn ctlz64(x: i64) -> i64; - - pub fn cttz8(x: i8) -> i8; - pub fn cttz16(x: i16) -> i16; - pub fn cttz32(x: i32) -> i32; - pub fn cttz64(x: i64) -> i64; - - pub fn bswap16(x: i16) -> i16; - pub fn bswap32(x: i32) -> i32; - pub fn bswap64(x: i64) -> i64; - - pub fn i8_add_with_overflow(x: i8, y: i8) -> (i8, bool); - pub fn i16_add_with_overflow(x: i16, y: i16) -> (i16, bool); - pub fn i32_add_with_overflow(x: i32, y: i32) -> (i32, bool); - pub fn i64_add_with_overflow(x: i64, y: i64) -> (i64, bool); - - pub fn u8_add_with_overflow(x: u8, y: u8) -> (u8, bool); - pub fn u16_add_with_overflow(x: u16, y: u16) -> (u16, bool); - pub fn u32_add_with_overflow(x: u32, y: u32) -> (u32, bool); - pub fn u64_add_with_overflow(x: u64, y: u64) -> (u64, bool); - - pub fn i8_sub_with_overflow(x: i8, y: i8) -> (i8, bool); - pub fn i16_sub_with_overflow(x: i16, y: i16) -> (i16, bool); - pub fn i32_sub_with_overflow(x: i32, y: i32) -> (i32, bool); - pub fn i64_sub_with_overflow(x: i64, y: i64) -> (i64, bool); - - pub fn u8_sub_with_overflow(x: u8, y: u8) -> (u8, bool); - pub fn u16_sub_with_overflow(x: u16, y: u16) -> (u16, bool); - pub fn u32_sub_with_overflow(x: u32, y: u32) -> (u32, bool); - pub fn u64_sub_with_overflow(x: u64, y: u64) -> (u64, bool); - - pub fn i8_mul_with_overflow(x: i8, y: i8) -> (i8, bool); - pub fn i16_mul_with_overflow(x: i16, y: i16) -> (i16, bool); - pub fn i32_mul_with_overflow(x: i32, y: i32) -> (i32, bool); - pub fn i64_mul_with_overflow(x: i64, y: i64) -> (i64, bool); - - pub fn u8_mul_with_overflow(x: u8, y: u8) -> (u8, bool); - pub fn u16_mul_with_overflow(x: u16, y: u16) -> (u16, bool); - pub fn u32_mul_with_overflow(x: u32, y: u32) -> (u32, bool); - pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool); -} - - -/// `TypeId` represents a globally unique identifier for a type -#[lang="type_id"] // This needs to be kept in lockstep with the code in trans/intrinsic.rs and - // middle/lang_items.rs -#[deriving(Eq, IterBytes)] -#[cfg(not(test))] -pub struct TypeId { - priv t: u64, -} - -#[cfg(not(test))] -impl TypeId { - /// Returns the `TypeId` of the type this generic function has been instantiated with - pub fn of() -> TypeId { - unsafe { type_id::() } - } -} diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index 87870ef0331..d3dae938b34 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -16,7 +16,6 @@ use libc::uintptr_t; pub mod dynamic_lib; pub mod finally; -pub mod intrinsics; pub mod simd; #[cfg(not(test))] pub mod lang; diff --git a/src/libstd/unstable/stack.rs b/src/libstd/unstable/stack.rs index 90c7888973a..655c209fec8 100644 --- a/src/libstd/unstable/stack.rs +++ b/src/libstd/unstable/stack.rs @@ -40,7 +40,7 @@ pub extern "C" fn rust_stack_exhausted() { use rt::local::Local; use rt::task::Task; use str::Str; - use unstable::intrinsics; + use intrinsics; unsafe { // We're calling this function because the stack just ran out. We need -- cgit 1.4.1-3-g733a5 From 3e57808a01407be24a35f69148d20b76341b162f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 16 Feb 2014 00:04:33 -0800 Subject: std: Move raw to std::raw Issue #1457 --- src/libgreen/context.rs | 2 +- src/libgreen/sched.rs | 2 +- src/libgreen/task.rs | 2 +- src/librustc/back/archive.rs | 2 +- src/libstd/c_str.rs | 2 +- src/libstd/cast.rs | 2 +- src/libstd/cleanup.rs | 2 +- src/libstd/lib.rs | 2 + src/libstd/managed.rs | 2 +- src/libstd/raw.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++ src/libstd/reflect.rs | 2 +- src/libstd/repr.rs | 2 +- src/libstd/rt/global_heap.rs | 2 +- src/libstd/rt/local_heap.rs | 2 +- src/libstd/rt/unwind.rs | 2 +- src/libstd/str.rs | 4 +- src/libstd/unstable/mod.rs | 1 - src/libstd/unstable/raw.rs | 95 ------------------------------------------- src/libstd/vec.rs | 4 +- src/libstd/vec_ng.rs | 2 +- 20 files changed, 117 insertions(+), 114 deletions(-) create mode 100644 src/libstd/raw.rs delete mode 100644 src/libstd/unstable/raw.rs (limited to 'src/libstd') diff --git a/src/libgreen/context.rs b/src/libgreen/context.rs index 58188ede13c..3f6dc299da5 100644 --- a/src/libgreen/context.rs +++ b/src/libgreen/context.rs @@ -13,7 +13,7 @@ use std::cast::{transmute, transmute_mut_unsafe, transmute_region, transmute_mut_region}; use stack::Stack; use std::unstable::stack; -use std::unstable::raw; +use std::raw; // FIXME #7761: Registers is boxed so that it is 16-byte aligned, for storing // SSE regs. It would be marginally better not to do this. In C++ we diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs index a966dff000a..f722744e23d 100644 --- a/src/libgreen/sched.rs +++ b/src/libgreen/sched.rs @@ -16,7 +16,7 @@ use std::rt::task::BlockedTask; use std::rt::task::Task; use std::sync::deque; use std::unstable::mutex::NativeMutex; -use std::unstable::raw; +use std::raw; use TaskState; use context::Context; diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs index e139cfa1025..1d7fb64896f 100644 --- a/src/libgreen/task.rs +++ b/src/libgreen/task.rs @@ -26,7 +26,7 @@ use std::rt::rtio; use std::rt::task::{Task, BlockedTask, SendMessage}; use std::task::TaskOpts; use std::unstable::mutex::NativeMutex; -use std::unstable::raw; +use std::raw; use context::Context; use coroutine::Coroutine; diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs index d5d784cc2de..6dec7550fec 100644 --- a/src/librustc/back/archive.rs +++ b/src/librustc/back/archive.rs @@ -22,7 +22,7 @@ use std::libc; use std::os; use std::run::{ProcessOptions, Process, ProcessOutput}; use std::str; -use std::unstable::raw; +use std::raw; use extra::tempfile::TempDir; use syntax::abi; diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index e6b0958617e..af5d9838186 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -79,7 +79,7 @@ use str; use vec::{ImmutableVector, MutableVector}; use vec; use rt::global_heap::malloc_raw; -use unstable::raw::Slice; +use raw::Slice; /// The representation of a C String. /// diff --git a/src/libstd/cast.rs b/src/libstd/cast.rs index c2db0c78205..8280553c1a3 100644 --- a/src/libstd/cast.rs +++ b/src/libstd/cast.rs @@ -113,7 +113,7 @@ pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T { #[cfg(test)] mod tests { use cast::{bump_box_refcount, transmute}; - use unstable::raw; + use raw; #[test] fn test_transmute_copy() { diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs index dd43d8e2971..39c7932cdc8 100644 --- a/src/libstd/cleanup.rs +++ b/src/libstd/cleanup.rs @@ -11,7 +11,7 @@ #[doc(hidden)]; use ptr; -use unstable::raw; +use raw; static RC_IMMORTAL : uint = 0x77777777; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 46958974484..65b908a9f56 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -198,6 +198,8 @@ pub mod reflect; pub mod unstable; #[experimental] pub mod intrinsics; +#[experimental] +pub mod raw; /* For internal use, not exported */ diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index 63196cd4f16..4cd99492ee4 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -15,7 +15,7 @@ /// Returns the refcount of a shared box (as just before calling this) #[inline] pub fn refcount(t: @T) -> uint { - use unstable::raw::Repr; + use raw::Repr; unsafe { (*t.repr()).ref_count - 1 } } diff --git a/src/libstd/raw.rs b/src/libstd/raw.rs new file mode 100644 index 00000000000..c7ba2ad3932 --- /dev/null +++ b/src/libstd/raw.rs @@ -0,0 +1,97 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(missing_doc)]; + +use cast; + +/// The representation of a Rust managed box +pub struct Box { + ref_count: uint, + drop_glue: fn(ptr: *mut u8), + prev: *mut Box, + next: *mut Box, + data: T +} + +/// The representation of a Rust vector +pub struct Vec { + fill: uint, + alloc: uint, + data: T +} + +/// The representation of a Rust string +pub type String = Vec; + +/// The representation of a Rust slice +pub struct Slice { + data: *T, + len: uint +} + +/// The representation of a Rust closure +pub struct Closure { + code: *(), + env: *(), +} + +/// The representation of a Rust procedure (`proc()`) +pub struct Procedure { + code: *(), + env: *(), +} + +/// This trait is meant to map equivalences between raw structs and their +/// corresponding rust values. +pub trait Repr { + /// This function "unwraps" a rust value (without consuming it) into its raw + /// struct representation. This can be used to read/write different values + /// for the struct. This is a safe method because by default it does not + /// give write-access to the struct returned. + #[inline] + fn repr(&self) -> T { unsafe { cast::transmute_copy(self) } } +} + +impl<'a, T> Repr> for &'a [T] {} +impl<'a> Repr> for &'a str {} +impl Repr<*Box> for @T {} +impl Repr<*Vec> for ~[T] {} +impl Repr<*String> for ~str {} + +#[cfg(test)] +mod tests { + use super::*; + + use cast; + + #[test] + fn synthesize_closure() { + unsafe { + let x = 10; + let f: |int| -> int = |y| x + y; + + assert_eq!(f(20), 30); + + let original_closure: Closure = cast::transmute(f); + + let actual_function_pointer = original_closure.code; + let environment = original_closure.env; + + let new_closure = Closure { + code: actual_function_pointer, + env: environment + }; + + let new_f: |int| -> int = cast::transmute(new_closure); + assert_eq!(new_f(20), 30); + } + } +} diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index 5ee840748e6..a9e70bd3c63 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -18,7 +18,7 @@ Runtime type reflection use intrinsics::{Disr, Opaque, TyDesc, TyVisitor}; use mem; -use unstable::raw; +use raw; /** * Trait for visitor that wishes to reflect on data. To use this, create a diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index 8e1a0714748..c1b276899d5 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -30,7 +30,7 @@ use str::StrSlice; use to_str::ToStr; use vec::OwnedVector; use intrinsics::{Disr, Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc}; -use unstable::raw; +use raw; macro_rules! try( ($me:expr, $e:expr) => ( match $e { diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 191d57a58fc..23b23cf8af0 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -11,7 +11,7 @@ use libc::{c_void, size_t, free, malloc, realloc}; use ptr::{RawPtr, mut_null}; use intrinsics::abort; -use unstable::raw; +use raw; use mem::size_of; #[inline] diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index 8a42cd73565..4ff25a34210 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -20,7 +20,7 @@ use ptr::RawPtr; use rt::global_heap; use rt::local::Local; use rt::task::Task; -use unstable::raw; +use raw; use vec::ImmutableVector; use vec_ng::Vec; diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index 127859b4275..16d677b5ff2 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -177,7 +177,7 @@ impl Unwinder { } pub fn try(&mut self, f: ||) { - use unstable::raw::Closure; + use raw::Closure; use libc::{c_void}; unsafe { diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 1c1b10bb14c..4d5eabbed10 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -104,7 +104,7 @@ use vec::{OwnedVector, OwnedCloneableVector, ImmutableVector, MutableVector}; use vec_ng::Vec; use default::Default; use to_bytes::{IterBytes, Cb}; -use unstable::raw::Repr; +use raw::Repr; /* Section: Creating a string @@ -1386,7 +1386,7 @@ pub mod raw { use str::{is_utf8, OwnedStr, StrSlice}; use vec; use vec::{MutableVector, ImmutableVector, OwnedVector}; - use unstable::raw::Slice; + use raw::Slice; /// Create a Rust string from a *u8 buffer of the given length pub unsafe fn from_buf_len(buf: *u8, len: uint) -> ~str { diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index d3dae938b34..9f37bfcddb9 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -21,7 +21,6 @@ pub mod simd; pub mod lang; pub mod sync; pub mod mutex; -pub mod raw; pub mod stack; /** diff --git a/src/libstd/unstable/raw.rs b/src/libstd/unstable/raw.rs deleted file mode 100644 index c25422d24e9..00000000000 --- a/src/libstd/unstable/raw.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cast; - -/// The representation of a Rust managed box -pub struct Box { - ref_count: uint, - drop_glue: fn(ptr: *mut u8), - prev: *mut Box, - next: *mut Box, - data: T -} - -/// The representation of a Rust vector -pub struct Vec { - fill: uint, - alloc: uint, - data: T -} - -/// The representation of a Rust string -pub type String = Vec; - -/// The representation of a Rust slice -pub struct Slice { - data: *T, - len: uint -} - -/// The representation of a Rust closure -pub struct Closure { - code: *(), - env: *(), -} - -/// The representation of a Rust procedure (`proc()`) -pub struct Procedure { - code: *(), - env: *(), -} - -/// This trait is meant to map equivalences between raw structs and their -/// corresponding rust values. -pub trait Repr { - /// This function "unwraps" a rust value (without consuming it) into its raw - /// struct representation. This can be used to read/write different values - /// for the struct. This is a safe method because by default it does not - /// give write-access to the struct returned. - #[inline] - fn repr(&self) -> T { unsafe { cast::transmute_copy(self) } } -} - -impl<'a, T> Repr> for &'a [T] {} -impl<'a> Repr> for &'a str {} -impl Repr<*Box> for @T {} -impl Repr<*Vec> for ~[T] {} -impl Repr<*String> for ~str {} - -#[cfg(test)] -mod tests { - use super::*; - - use cast; - - #[test] - fn synthesize_closure() { - unsafe { - let x = 10; - let f: |int| -> int = |y| x + y; - - assert_eq!(f(20), 30); - - let original_closure: Closure = cast::transmute(f); - - let actual_function_pointer = original_closure.code; - let environment = original_closure.env; - - let new_closure = Closure { - code: actual_function_pointer, - env: environment - }; - - let new_f: |int| -> int = cast::transmute(new_closure); - assert_eq!(new_f(20), 30); - } - } -} diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 0adc6083f6b..00617af05b1 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -122,7 +122,7 @@ use mem::size_of; use kinds::marker; use uint; use unstable::finally::try_finally; -use unstable::raw::{Repr, Slice, Vec}; +use raw::{Repr, Slice, Vec}; /** * Creates and initializes an owned vector. @@ -2488,7 +2488,7 @@ pub mod raw { use ptr; use ptr::RawPtr; use vec::{with_capacity, MutableVector, OwnedVector}; - use unstable::raw::Slice; + use raw::Slice; /** * Form a slice from a pointer and length (as a number of units, diff --git a/src/libstd/vec_ng.rs b/src/libstd/vec_ng.rs index 114f34963e2..3532e7b26a4 100644 --- a/src/libstd/vec_ng.rs +++ b/src/libstd/vec_ng.rs @@ -24,7 +24,7 @@ use option::{None, Option, Some}; use ptr::RawPtr; use ptr; use rt::global_heap::{malloc_raw, realloc_raw}; -use unstable::raw::Slice; +use raw::Slice; use vec::{ImmutableVector, Items, MutItems, MutableVector, RevItems}; pub struct Vec { -- cgit 1.4.1-3-g733a5 From 96b299e1f08e2b6bbb8c03dfaa2881898dc6a0cb Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 16 Feb 2014 20:16:23 -0800 Subject: std: Remove unstable::lang Put the lonely lang items here closer to the code they are calling. --- src/libstd/rt/local_heap.rs | 19 ++++++++++++++++- src/libstd/rt/unwind.rs | 18 ++++++++++++++++ src/libstd/unstable/lang.rs | 52 --------------------------------------------- src/libstd/unstable/mod.rs | 2 -- 4 files changed, 36 insertions(+), 55 deletions(-) delete mode 100644 src/libstd/unstable/lang.rs (limited to 'src/libstd') diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index 4ff25a34210..29b3dcaa4f2 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -276,6 +276,14 @@ impl Drop for MemoryRegion { } } + +#[cfg(not(test))] +#[lang="malloc"] +#[inline] +pub unsafe fn local_malloc_(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 { + local_malloc(drop_glue, size, align) +} + #[inline] pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 { // FIXME: Unsafe borrow for speed. Lame. @@ -288,7 +296,16 @@ pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> * } } -// A little compatibility function +#[cfg(not(test))] +#[lang="free"] +#[inline] +pub unsafe fn local_free_(ptr: *u8) { + local_free(ptr) +} + +// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from +// inside a landing pad may corrupt the state of the exception handler. If a +// problem occurs, call exit instead. #[inline] pub unsafe fn local_free(ptr: *u8) { // FIXME: Unsafe borrow for speed. Lame. diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index 16d677b5ff2..b9459aed582 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -376,6 +376,24 @@ pub mod eabi { } } +#[cold] +#[lang="fail_"] +#[cfg(not(test))] +pub fn fail_(expr: *u8, file: *u8, line: uint) -> ! { + begin_unwind_raw(expr, file, line); +} + +#[cold] +#[lang="fail_bounds_check"] +#[cfg(not(test))] +pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! { + use c_str::ToCStr; + + let msg = format!("index out of bounds: the len is {} but the index is {}", + len as uint, index as uint); + msg.with_c_str(|buf| fail_(buf as *u8, file, line)) +} + /// This is the entry point of unwinding for things like lang items and such. /// The arguments are normally generated by the compiler, and need to /// have static lifetimes. diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs deleted file mode 100644 index 8818cb0d270..00000000000 --- a/src/libstd/unstable/lang.rs +++ /dev/null @@ -1,52 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Runtime calls emitted by the compiler. - -use c_str::CString; -use libc::c_char; -use cast; -use option::Some; - -#[cold] -#[lang="fail_"] -pub fn fail_(expr: *u8, file: *u8, line: uint) -> ! { - ::rt::begin_unwind_raw(expr, file, line); -} - -#[cold] -#[lang="fail_bounds_check"] -pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! { - let msg = format!("index out of bounds: the len is {} but the index is {}", - len as uint, index as uint); - - let file_str = match unsafe { CString::new(file as *c_char, false) }.as_str() { - // This transmute is safe because `file` is always stored in rodata. - Some(s) => unsafe { cast::transmute::<&str, &'static str>(s) }, - None => "file wasn't UTF-8 safe" - }; - - ::rt::begin_unwind(msg, file_str, line) -} - -#[lang="malloc"] -#[inline] -pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 { - ::rt::local_heap::local_malloc(drop_glue, size, align) -} - -// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from -// inside a landing pad may corrupt the state of the exception handler. If a -// problem occurs, call exit instead. -#[lang="free"] -#[inline] -pub unsafe fn local_free(ptr: *u8) { - ::rt::local_heap::local_free(ptr); -} diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index 9f37bfcddb9..1a4862fd733 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -17,8 +17,6 @@ pub mod dynamic_lib; pub mod finally; pub mod simd; -#[cfg(not(test))] -pub mod lang; pub mod sync; pub mod mutex; pub mod stack; -- cgit 1.4.1-3-g733a5 From db111846b58253c723750be280a478ed7d27d879 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 16 Feb 2014 21:37:12 -0800 Subject: std: Move unstable::stack to rt::stack --- src/libgreen/context.rs | 2 +- src/libnative/task.rs | 2 +- src/libstd/rt/mod.rs | 3 + src/libstd/rt/stack.rs | 276 +++++++++++++++++++++++++++++++++++++++++++ src/libstd/rt/thread.rs | 6 +- src/libstd/unstable/mod.rs | 1 - src/libstd/unstable/stack.rs | 276 ------------------------------------------- 7 files changed, 284 insertions(+), 282 deletions(-) create mode 100644 src/libstd/rt/stack.rs delete mode 100644 src/libstd/unstable/stack.rs (limited to 'src/libstd') diff --git a/src/libgreen/context.rs b/src/libgreen/context.rs index 3f6dc299da5..1d79f3f14c5 100644 --- a/src/libgreen/context.rs +++ b/src/libgreen/context.rs @@ -12,7 +12,7 @@ use std::uint; use std::cast::{transmute, transmute_mut_unsafe, transmute_region, transmute_mut_region}; use stack::Stack; -use std::unstable::stack; +use std::rt::stack; use std::raw; // FIXME #7761: Registers is boxed so that it is 16-byte aligned, for storing diff --git a/src/libnative/task.rs b/src/libnative/task.rs index b0f063ff06e..ccfc040e7df 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -23,7 +23,7 @@ use std::rt::thread::Thread; use std::rt; use std::task::TaskOpts; use std::unstable::mutex::NativeMutex; -use std::unstable::stack; +use std::rt::stack; use io; use task; diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index b751c57c0fa..2f1a6989092 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -128,6 +128,9 @@ pub mod args; // Support for running procedures when a program has exited. mod at_exit_imp; +// Stack overflow protection +pub mod stack; + /// The default error code of the rust runtime if the main task fails instead /// of exiting cleanly. pub static DEFAULT_ERROR_CODE: int = 101; diff --git a/src/libstd/rt/stack.rs b/src/libstd/rt/stack.rs new file mode 100644 index 00000000000..655c209fec8 --- /dev/null +++ b/src/libstd/rt/stack.rs @@ -0,0 +1,276 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Rust stack-limit management +//! +//! Currently Rust uses a segmented-stack-like scheme in order to detect stack +//! overflow for rust tasks. In this scheme, the prologue of all functions are +//! preceded with a check to see whether the current stack limits are being +//! exceeded. +//! +//! This module provides the functionality necessary in order to manage these +//! stack limits (which are stored in platform-specific locations). The +//! functions here are used at the borders of the task lifetime in order to +//! manage these limits. +//! +//! This function is an unstable module because this scheme for stack overflow +//! detection is not guaranteed to continue in the future. Usage of this module +//! is discouraged unless absolutely necessary. + +pub static RED_ZONE: uint = 20 * 1024; + +/// This function is invoked from rust's current __morestack function. Segmented +/// stacks are currently not enabled as segmented stacks, but rather one giant +/// stack segment. This means that whenever we run out of stack, we want to +/// truly consider it to be stack overflow rather than allocating a new stack. +#[no_mangle] // - this is called from C code +#[no_split_stack] // - it would be sad for this function to trigger __morestack +#[doc(hidden)] // - Function must be `pub` to get exported, but it's + // irrelevant for documentation purposes. +#[cfg(not(test))] // in testing, use the original libstd's version +pub extern "C" fn rust_stack_exhausted() { + use option::None; + use rt::local::Local; + use rt::task::Task; + use str::Str; + use intrinsics; + + unsafe { + // We're calling this function because the stack just ran out. We need + // to call some other rust functions, but if we invoke the functions + // right now it'll just trigger this handler being called again. In + // order to alleviate this, we move the stack limit to be inside of the + // red zone that was allocated for exactly this reason. + let limit = get_sp_limit(); + record_sp_limit(limit - RED_ZONE / 2); + + // This probably isn't the best course of action. Ideally one would want + // to unwind the stack here instead of just aborting the entire process. + // This is a tricky problem, however. There's a few things which need to + // be considered: + // + // 1. We're here because of a stack overflow, yet unwinding will run + // destructors and hence arbitrary code. What if that code overflows + // the stack? One possibility is to use the above allocation of an + // extra 10k to hope that we don't hit the limit, and if we do then + // abort the whole program. Not the best, but kind of hard to deal + // with unless we want to switch stacks. + // + // 2. LLVM will optimize functions based on whether they can unwind or + // not. It will flag functions with 'nounwind' if it believes that + // the function cannot trigger unwinding, but if we do unwind on + // stack overflow then it means that we could unwind in any function + // anywhere. We would have to make sure that LLVM only places the + // nounwind flag on functions which don't call any other functions. + // + // 3. The function that overflowed may have owned arguments. These + // arguments need to have their destructors run, but we haven't even + // begun executing the function yet, so unwinding will not run the + // any landing pads for these functions. If this is ignored, then + // the arguments will just be leaked. + // + // Exactly what to do here is a very delicate topic, and is possibly + // still up in the air for what exactly to do. Some relevant issues: + // + // #3555 - out-of-stack failure leaks arguments + // #3695 - should there be a stack limit? + // #9855 - possible strategies which could be taken + // #9854 - unwinding on windows through __morestack has never worked + // #2361 - possible implementation of not using landing pads + + let mut task = Local::borrow(None::); + let n = task.get().name.as_ref() + .map(|n| n.as_slice()).unwrap_or(""); + + // See the message below for why this is not emitted to the + // task's logger. This has the additional conundrum of the + // logger may not be initialized just yet, meaning that an FFI + // call would happen to initialized it (calling out to libuv), + // and the FFI call needs 2MB of stack when we just ran out. + println!("task '{}' has overflowed its stack", n); + + intrinsics::abort(); + } +} + +#[inline(always)] +pub unsafe fn record_stack_bounds(stack_lo: uint, stack_hi: uint) { + // When the old runtime had segmented stacks, it used a calculation that was + // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic + // symbol resolution, llvm function calls, etc. In theory this red zone + // value is 0, but it matters far less when we have gigantic stacks because + // we don't need to be so exact about our stack budget. The "fudge factor" + // was because LLVM doesn't emit a stack check for functions < 256 bytes in + // size. Again though, we have giant stacks, so we round all these + // calculations up to the nice round number of 20k. + record_sp_limit(stack_lo + RED_ZONE); + + return target_record_stack_bounds(stack_lo, stack_hi); + + #[cfg(not(windows))] #[cfg(not(target_arch = "x86_64"))] #[inline(always)] + unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {} + #[cfg(windows, target_arch = "x86_64")] #[inline(always)] + unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) { + // Windows compiles C functions which may check the stack bounds. This + // means that if we want to perform valid FFI on windows, then we need + // to ensure that the stack bounds are what they truly are for this + // task. More info can be found at: + // https://github.com/mozilla/rust/issues/3445#issuecomment-26114839 + // + // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom) + asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile"); + asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile"); + } +} + +/// Records the current limit of the stack as specified by `end`. +/// +/// This is stored in an OS-dependent location, likely inside of the thread +/// local storage. The location that the limit is stored is a pre-ordained +/// location because it's where LLVM has emitted code to check. +/// +/// Note that this cannot be called under normal circumstances. This function is +/// changing the stack limit, so upon returning any further function calls will +/// possibly be triggering the morestack logic if you're not careful. +/// +/// Also note that this and all of the inside functions are all flagged as +/// "inline(always)" because they're messing around with the stack limits. This +/// would be unfortunate for the functions themselves to trigger a morestack +/// invocation (if they were an actual function call). +#[inline(always)] +pub unsafe fn record_sp_limit(limit: uint) { + return target_record_sp_limit(limit); + + // x86-64 + #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)] + unsafe fn target_record_sp_limit(limit: uint) { + asm!("movq $$0x60+90*8, %rsi + movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile") + } + #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)] + unsafe fn target_record_sp_limit(limit: uint) { + asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile") + } + #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)] + unsafe fn target_record_sp_limit(limit: uint) { + // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block + // store this inside of the "arbitrary data slot", but double the size + // because this is 64 bit instead of 32 bit + asm!("movq $0, %gs:0x28" :: "r"(limit) :: "volatile") + } + #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)] + unsafe fn target_record_sp_limit(limit: uint) { + asm!("movq $0, %fs:24" :: "r"(limit) :: "volatile") + } + + // x86 + #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)] + unsafe fn target_record_sp_limit(limit: uint) { + asm!("movl $$0x48+90*4, %eax + movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile") + } + #[cfg(target_arch = "x86", target_os = "linux")] + #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)] + unsafe fn target_record_sp_limit(limit: uint) { + asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile") + } + #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)] + unsafe fn target_record_sp_limit(limit: uint) { + // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block + // store this inside of the "arbitrary data slot" + asm!("movl $0, %fs:0x14" :: "r"(limit) :: "volatile") + } + + // mips, arm - Some brave soul can port these to inline asm, but it's over + // my head personally + #[cfg(target_arch = "mips")] + #[cfg(target_arch = "arm")] #[inline(always)] + unsafe fn target_record_sp_limit(limit: uint) { + use libc::c_void; + return record_sp_limit(limit as *c_void); + extern { + fn record_sp_limit(limit: *c_void); + } + } +} + +/// The counterpart of the function above, this function will fetch the current +/// stack limit stored in TLS. +/// +/// Note that all of these functions are meant to be exact counterparts of their +/// brethren above, except that the operands are reversed. +/// +/// As with the setter, this function does not have a __morestack header and can +/// therefore be called in a "we're out of stack" situation. +#[inline(always)] +pub unsafe fn get_sp_limit() -> uint { + return target_get_sp_limit(); + + // x86-64 + #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)] + unsafe fn target_get_sp_limit() -> uint { + let limit; + asm!("movq $$0x60+90*8, %rsi + movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile"); + return limit; + } + #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)] + unsafe fn target_get_sp_limit() -> uint { + let limit; + asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile"); + return limit; + } + #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)] + unsafe fn target_get_sp_limit() -> uint { + let limit; + asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile"); + return limit; + } + #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)] + unsafe fn target_get_sp_limit() -> uint { + let limit; + asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile"); + return limit; + } + + // x86 + #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)] + unsafe fn target_get_sp_limit() -> uint { + let limit; + asm!("movl $$0x48+90*4, %eax + movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile"); + return limit; + } + #[cfg(target_arch = "x86", target_os = "linux")] + #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)] + unsafe fn target_get_sp_limit() -> uint { + let limit; + asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile"); + return limit; + } + #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)] + unsafe fn target_get_sp_limit() -> uint { + let limit; + asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile"); + return limit; + } + + // mips, arm - Some brave soul can port these to inline asm, but it's over + // my head personally + #[cfg(target_arch = "mips")] + #[cfg(target_arch = "arm")] #[inline(always)] + unsafe fn target_get_sp_limit() -> uint { + use libc::c_void; + return get_sp_limit() as uint; + extern { + fn get_sp_limit() -> *c_void; + } + } +} diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs index b443182c157..7b24c94b518 100644 --- a/src/libstd/rt/thread.rs +++ b/src/libstd/rt/thread.rs @@ -41,7 +41,7 @@ static DEFAULT_STACK_SIZE: uint = 1024 * 1024; // and invoke it. #[no_split_stack] extern fn thread_start(main: *libc::c_void) -> imp::rust_thread_return { - use unstable::stack; + use rt::stack; unsafe { stack::record_stack_bounds(0, uint::MAX); let f: ~proc() = cast::transmute(main); @@ -150,7 +150,7 @@ mod imp { use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL, LPVOID, DWORD, LPDWORD, HANDLE}; use ptr; - use unstable::stack::RED_ZONE; + use rt::stack::RED_ZONE; pub type rust_thread = HANDLE; pub type rust_thread_return = DWORD; @@ -208,7 +208,7 @@ mod imp { use mem; use os; use ptr; - use unstable::stack::RED_ZONE; + use rt::stack::RED_ZONE; pub type rust_thread = libc::pthread_t; pub type rust_thread_return = *u8; diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index 1a4862fd733..7bee0cf48ee 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -19,7 +19,6 @@ pub mod finally; pub mod simd; pub mod sync; pub mod mutex; -pub mod stack; /** diff --git a/src/libstd/unstable/stack.rs b/src/libstd/unstable/stack.rs deleted file mode 100644 index 655c209fec8..00000000000 --- a/src/libstd/unstable/stack.rs +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Rust stack-limit management -//! -//! Currently Rust uses a segmented-stack-like scheme in order to detect stack -//! overflow for rust tasks. In this scheme, the prologue of all functions are -//! preceded with a check to see whether the current stack limits are being -//! exceeded. -//! -//! This module provides the functionality necessary in order to manage these -//! stack limits (which are stored in platform-specific locations). The -//! functions here are used at the borders of the task lifetime in order to -//! manage these limits. -//! -//! This function is an unstable module because this scheme for stack overflow -//! detection is not guaranteed to continue in the future. Usage of this module -//! is discouraged unless absolutely necessary. - -pub static RED_ZONE: uint = 20 * 1024; - -/// This function is invoked from rust's current __morestack function. Segmented -/// stacks are currently not enabled as segmented stacks, but rather one giant -/// stack segment. This means that whenever we run out of stack, we want to -/// truly consider it to be stack overflow rather than allocating a new stack. -#[no_mangle] // - this is called from C code -#[no_split_stack] // - it would be sad for this function to trigger __morestack -#[doc(hidden)] // - Function must be `pub` to get exported, but it's - // irrelevant for documentation purposes. -#[cfg(not(test))] // in testing, use the original libstd's version -pub extern "C" fn rust_stack_exhausted() { - use option::None; - use rt::local::Local; - use rt::task::Task; - use str::Str; - use intrinsics; - - unsafe { - // We're calling this function because the stack just ran out. We need - // to call some other rust functions, but if we invoke the functions - // right now it'll just trigger this handler being called again. In - // order to alleviate this, we move the stack limit to be inside of the - // red zone that was allocated for exactly this reason. - let limit = get_sp_limit(); - record_sp_limit(limit - RED_ZONE / 2); - - // This probably isn't the best course of action. Ideally one would want - // to unwind the stack here instead of just aborting the entire process. - // This is a tricky problem, however. There's a few things which need to - // be considered: - // - // 1. We're here because of a stack overflow, yet unwinding will run - // destructors and hence arbitrary code. What if that code overflows - // the stack? One possibility is to use the above allocation of an - // extra 10k to hope that we don't hit the limit, and if we do then - // abort the whole program. Not the best, but kind of hard to deal - // with unless we want to switch stacks. - // - // 2. LLVM will optimize functions based on whether they can unwind or - // not. It will flag functions with 'nounwind' if it believes that - // the function cannot trigger unwinding, but if we do unwind on - // stack overflow then it means that we could unwind in any function - // anywhere. We would have to make sure that LLVM only places the - // nounwind flag on functions which don't call any other functions. - // - // 3. The function that overflowed may have owned arguments. These - // arguments need to have their destructors run, but we haven't even - // begun executing the function yet, so unwinding will not run the - // any landing pads for these functions. If this is ignored, then - // the arguments will just be leaked. - // - // Exactly what to do here is a very delicate topic, and is possibly - // still up in the air for what exactly to do. Some relevant issues: - // - // #3555 - out-of-stack failure leaks arguments - // #3695 - should there be a stack limit? - // #9855 - possible strategies which could be taken - // #9854 - unwinding on windows through __morestack has never worked - // #2361 - possible implementation of not using landing pads - - let mut task = Local::borrow(None::); - let n = task.get().name.as_ref() - .map(|n| n.as_slice()).unwrap_or(""); - - // See the message below for why this is not emitted to the - // task's logger. This has the additional conundrum of the - // logger may not be initialized just yet, meaning that an FFI - // call would happen to initialized it (calling out to libuv), - // and the FFI call needs 2MB of stack when we just ran out. - println!("task '{}' has overflowed its stack", n); - - intrinsics::abort(); - } -} - -#[inline(always)] -pub unsafe fn record_stack_bounds(stack_lo: uint, stack_hi: uint) { - // When the old runtime had segmented stacks, it used a calculation that was - // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic - // symbol resolution, llvm function calls, etc. In theory this red zone - // value is 0, but it matters far less when we have gigantic stacks because - // we don't need to be so exact about our stack budget. The "fudge factor" - // was because LLVM doesn't emit a stack check for functions < 256 bytes in - // size. Again though, we have giant stacks, so we round all these - // calculations up to the nice round number of 20k. - record_sp_limit(stack_lo + RED_ZONE); - - return target_record_stack_bounds(stack_lo, stack_hi); - - #[cfg(not(windows))] #[cfg(not(target_arch = "x86_64"))] #[inline(always)] - unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {} - #[cfg(windows, target_arch = "x86_64")] #[inline(always)] - unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) { - // Windows compiles C functions which may check the stack bounds. This - // means that if we want to perform valid FFI on windows, then we need - // to ensure that the stack bounds are what they truly are for this - // task. More info can be found at: - // https://github.com/mozilla/rust/issues/3445#issuecomment-26114839 - // - // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom) - asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile"); - asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile"); - } -} - -/// Records the current limit of the stack as specified by `end`. -/// -/// This is stored in an OS-dependent location, likely inside of the thread -/// local storage. The location that the limit is stored is a pre-ordained -/// location because it's where LLVM has emitted code to check. -/// -/// Note that this cannot be called under normal circumstances. This function is -/// changing the stack limit, so upon returning any further function calls will -/// possibly be triggering the morestack logic if you're not careful. -/// -/// Also note that this and all of the inside functions are all flagged as -/// "inline(always)" because they're messing around with the stack limits. This -/// would be unfortunate for the functions themselves to trigger a morestack -/// invocation (if they were an actual function call). -#[inline(always)] -pub unsafe fn record_sp_limit(limit: uint) { - return target_record_sp_limit(limit); - - // x86-64 - #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - asm!("movq $$0x60+90*8, %rsi - movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile") - } - #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile") - } - #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block - // store this inside of the "arbitrary data slot", but double the size - // because this is 64 bit instead of 32 bit - asm!("movq $0, %gs:0x28" :: "r"(limit) :: "volatile") - } - #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - asm!("movq $0, %fs:24" :: "r"(limit) :: "volatile") - } - - // x86 - #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - asm!("movl $$0x48+90*4, %eax - movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile") - } - #[cfg(target_arch = "x86", target_os = "linux")] - #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile") - } - #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block - // store this inside of the "arbitrary data slot" - asm!("movl $0, %fs:0x14" :: "r"(limit) :: "volatile") - } - - // mips, arm - Some brave soul can port these to inline asm, but it's over - // my head personally - #[cfg(target_arch = "mips")] - #[cfg(target_arch = "arm")] #[inline(always)] - unsafe fn target_record_sp_limit(limit: uint) { - use libc::c_void; - return record_sp_limit(limit as *c_void); - extern { - fn record_sp_limit(limit: *c_void); - } - } -} - -/// The counterpart of the function above, this function will fetch the current -/// stack limit stored in TLS. -/// -/// Note that all of these functions are meant to be exact counterparts of their -/// brethren above, except that the operands are reversed. -/// -/// As with the setter, this function does not have a __morestack header and can -/// therefore be called in a "we're out of stack" situation. -#[inline(always)] -pub unsafe fn get_sp_limit() -> uint { - return target_get_sp_limit(); - - // x86-64 - #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)] - unsafe fn target_get_sp_limit() -> uint { - let limit; - asm!("movq $$0x60+90*8, %rsi - movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile"); - return limit; - } - #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)] - unsafe fn target_get_sp_limit() -> uint { - let limit; - asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile"); - return limit; - } - #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)] - unsafe fn target_get_sp_limit() -> uint { - let limit; - asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile"); - return limit; - } - #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)] - unsafe fn target_get_sp_limit() -> uint { - let limit; - asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile"); - return limit; - } - - // x86 - #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)] - unsafe fn target_get_sp_limit() -> uint { - let limit; - asm!("movl $$0x48+90*4, %eax - movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile"); - return limit; - } - #[cfg(target_arch = "x86", target_os = "linux")] - #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)] - unsafe fn target_get_sp_limit() -> uint { - let limit; - asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile"); - return limit; - } - #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)] - unsafe fn target_get_sp_limit() -> uint { - let limit; - asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile"); - return limit; - } - - // mips, arm - Some brave soul can port these to inline asm, but it's over - // my head personally - #[cfg(target_arch = "mips")] - #[cfg(target_arch = "arm")] #[inline(always)] - unsafe fn target_get_sp_limit() -> uint { - use libc::c_void; - return get_sp_limit() as uint; - extern { - fn get_sp_limit() -> *c_void; - } - } -} -- cgit 1.4.1-3-g733a5