]> git.lizzy.rs Git - rust.git/commitdiff
std: Internalize almost all of `std::rt`
authorAlex Crichton <alex@alexcrichton.com>
Tue, 8 Sep 2015 22:53:46 +0000 (15:53 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 11 Sep 2015 18:19:20 +0000 (11:19 -0700)
This commit does some refactoring to make almost all of the `std::rt` private.
Specifically, the following items are no longer part of its API:

* DEFAULT_ERROR_CODE
* backtrace
* unwind
* args
* at_exit
* cleanup
* heap (this is just alloc::heap)
* min_stack
* util

The module is now tagged as `#[doc(hidden)]` as the only purpose it's serve is
an entry point for the `panic!` macro via the `begin_unwind` and
`begin_unwind_fmt` reexports.

43 files changed:
src/doc/nomicon/destructors.md
src/doc/nomicon/vec-alloc.md
src/doc/nomicon/vec-final.md
src/libarena/lib.rs
src/liblog/lib.rs
src/libstd/collections/hash/table.rs
src/libstd/io/lazy.rs
src/libstd/panicking.rs
src/libstd/process.rs
src/libstd/rt.rs [new file with mode: 0644]
src/libstd/rt/args.rs [deleted file]
src/libstd/rt/at_exit_imp.rs [deleted file]
src/libstd/rt/backtrace.rs [deleted file]
src/libstd/rt/dwarf/eh.rs [deleted file]
src/libstd/rt/dwarf/mod.rs [deleted file]
src/libstd/rt/libunwind.rs [deleted file]
src/libstd/rt/macros.rs [deleted file]
src/libstd/rt/mod.rs [deleted file]
src/libstd/rt/unwind/gcc.rs [deleted file]
src/libstd/rt/unwind/mod.rs [deleted file]
src/libstd/rt/unwind/seh.rs [deleted file]
src/libstd/rt/unwind/seh64_gnu.rs [deleted file]
src/libstd/rt/util.rs [deleted file]
src/libstd/sys/common/args.rs [new file with mode: 0644]
src/libstd/sys/common/at_exit_imp.rs [new file with mode: 0644]
src/libstd/sys/common/backtrace.rs
src/libstd/sys/common/dwarf/eh.rs [new file with mode: 0644]
src/libstd/sys/common/dwarf/mod.rs [new file with mode: 0644]
src/libstd/sys/common/libunwind.rs [new file with mode: 0644]
src/libstd/sys/common/mod.rs
src/libstd/sys/common/unwind/gcc.rs [new file with mode: 0644]
src/libstd/sys/common/unwind/mod.rs [new file with mode: 0644]
src/libstd/sys/common/unwind/seh.rs [new file with mode: 0644]
src/libstd/sys/common/unwind/seh64_gnu.rs [new file with mode: 0644]
src/libstd/sys/common/util.rs [new file with mode: 0644]
src/libstd/sys/unix/mod.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/stack_overflow.rs
src/libstd/sys/windows/mod.rs
src/libstd/sys/windows/net.rs
src/libstd/sys/windows/stack_overflow.rs
src/libstd/sys/windows/thread_local.rs
src/libstd/thread/mod.rs

index 29a866063e99674e7fd33738ff15001f30b992d3..4492e2a92fae9e95aac56b0277e9b2a3626baa48 100644 (file)
@@ -26,13 +26,16 @@ this is totally fine.
 For instance, a custom implementation of `Box` might write `Drop` like this:
 
 ```rust
-#![feature(heap_api, core_intrinsics, unique)]
+#![feature(alloc, heap_api, core_intrinsics, unique)]
+
+extern crate alloc;
 
-use std::rt::heap;
 use std::ptr::Unique;
 use std::intrinsics::drop_in_place;
 use std::mem;
 
+use alloc::heap;
+
 struct Box<T>{ ptr: Unique<T> }
 
 impl<T> Drop for Box<T> {
@@ -45,6 +48,7 @@ impl<T> Drop for Box<T> {
         }
     }
 }
+# fn main() {}
 ```
 
 and this works fine because when Rust goes to drop the `ptr` field it just sees
@@ -54,13 +58,16 @@ use-after-free the `ptr` because when drop exits, it becomes inacessible.
 However this wouldn't work:
 
 ```rust
-#![feature(heap_api, core_intrinsics, unique)]
+#![feature(alloc, heap_api, core_intrinsics, unique)]
+
+extern crate alloc;
 
-use std::rt::heap;
 use std::ptr::Unique;
 use std::intrinsics::drop_in_place;
 use std::mem;
 
+use alloc::heap;
+
 struct Box<T>{ ptr: Unique<T> }
 
 impl<T> Drop for Box<T> {
@@ -87,6 +94,7 @@ impl<T> Drop for SuperBox<T> {
         }
     }
 }
+# fn main() {}
 ```
 
 After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will
@@ -129,13 +137,16 @@ The classic safe solution to overriding recursive drop and allowing moving out
 of Self during `drop` is to use an Option:
 
 ```rust
-#![feature(heap_api, core_intrinsics, unique)]
+#![feature(alloc, heap_api, core_intrinsics, unique)]
+
+extern crate alloc;
 
-use std::rt::heap;
 use std::ptr::Unique;
 use std::intrinsics::drop_in_place;
 use std::mem;
 
+use alloc::heap;
+
 struct Box<T>{ ptr: Unique<T> }
 
 impl<T> Drop for Box<T> {
@@ -165,6 +176,7 @@ impl<T> Drop for SuperBox<T> {
         }
     }
 }
+# fn main() {}
 ```
 
 However this has fairly odd semantics: you're saying that a field that *should*
index fc7feba2356d5a4fb742a5b9ea06a99d32e86085..c2ae1a4eb6d26ac1e8ad82de7e7e9aa2c0947e68 100644 (file)
@@ -9,7 +9,7 @@ This is perfectly fine because we already have `cap == 0` as our sentinel for no
 allocation. We don't even need to handle it specially in almost any code because
 we usually need to check if `cap > len` or `len > 0` anyway. The traditional
 Rust value to put here is `0x01`. The standard library actually exposes this
-as `std::rt::heap::EMPTY`. There are quite a few places where we'll
+as `alloc::heap::EMPTY`. There are quite a few places where we'll
 want to use `heap::EMPTY` because there's no real allocation to talk about but
 `null` would make the compiler do bad things.
 
@@ -20,11 +20,12 @@ the `heap` API anyway, so let's just get that dependency over with.
 So:
 
 ```rust,ignore
-#![feature(heap_api)]
+#![feature(alloc, heap_api)]
 
-use std::rt::heap::EMPTY;
 use std::mem;
 
+use alloc::heap::EMPTY;
+
 impl<T> Vec<T> {
     fn new() -> Self {
         assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");
index ba4537f164093d78f83c89bbb8d28653fbe1fda9..52c22f65076f9def84f83bc2e57955e1bf49ea19 100644 (file)
@@ -2,17 +2,16 @@
 
 ```rust
 #![feature(unique)]
-#![feature(heap_api)]
+#![feature(alloc, heap_api)]
+
+extern crate alloc;
 
 use std::ptr::{Unique, self};
-use std::rt::heap;
 use std::mem;
 use std::ops::{Deref, DerefMut};
 use std::marker::PhantomData;
 
-
-
-
+use alloc::heap;
 
 struct RawVec<T> {
     ptr: Unique<T>,
index f48443e52b3e9350ffb6263693af807c79c2324f..57e82720e8beaf3fc0a4a9c645a2b79d1a9c47c5 100644 (file)
@@ -49,7 +49,8 @@
 use std::mem;
 use std::ptr;
 use std::rc::Rc;
-use std::rt::heap::{allocate, deallocate};
+
+use alloc::heap::{allocate, deallocate};
 
 // The way arena uses arrays is really deeply awful. The arrays are
 // allocated, and have capacities reserved, but the fill for the array
index 4517c2f915773a78b86267277188734874df8457..d59e40fb1493c89827ea8052d472288137068fbd 100644 (file)
 #![feature(box_syntax)]
 #![feature(const_fn)]
 #![feature(iter_cmp)]
-#![feature(rt)]
 #![feature(staged_api)]
 #![feature(static_mutex)]
 
 use std::mem;
 use std::env;
 use std::ptr;
-use std::rt;
 use std::slice;
 use std::sync::{Once, StaticMutex};
 
@@ -292,7 +290,6 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
         let _g = LOCK.lock();
         match FILTER as usize {
             0 => {}
-            1 => panic!("cannot log after main thread has exited"),
             n => {
                 let filter = mem::transmute::<_, &String>(n);
                 if !args.to_string().contains(filter) {
@@ -385,9 +382,6 @@ pub fn mod_enabled(level: u32, module: &str) -> bool {
     let _g = LOCK.lock();
     unsafe {
         assert!(DIRECTIVES as usize != 0);
-        assert!(DIRECTIVES as usize != 1,
-                "cannot log after the main thread has exited");
-
         enabled(level, module, (*DIRECTIVES).iter())
     }
 }
@@ -442,19 +436,6 @@ fn init() {
 
         assert!(DIRECTIVES.is_null());
         DIRECTIVES = Box::into_raw(box directives);
-
-        // Schedule the cleanup for the globals for when the runtime exits.
-        let _ = rt::at_exit(move || {
-            let _g = LOCK.lock();
-            assert!(!DIRECTIVES.is_null());
-            let _directives = Box::from_raw(DIRECTIVES);
-            DIRECTIVES = 1 as *mut _;
-
-            if !FILTER.is_null() {
-                let _filter = Box::from_raw(FILTER);
-                FILTER = 1 as *mut _;
-            }
-        });
     }
 }
 
index e3601f1349c32d5fca6a5fc5af63e24623afdc33..f8bd791f6819c16cdc14f5e3ffce7e3a029c36f7 100644 (file)
@@ -8,23 +8,20 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use self::BucketState::*;
+use alloc::heap::{allocate, deallocate, EMPTY};
 
-use clone::Clone;
 use cmp;
 use hash::{Hash, Hasher};
-use iter::{Iterator, ExactSizeIterator};
-use marker::{Copy, Send, Sync, Sized, self};
+use marker;
 use mem::{align_of, size_of};
 use mem;
 use num::wrapping::OverflowingOps;
-use ops::{Deref, DerefMut, Drop};
-use option::Option;
-use option::Option::{Some, None};
+use ops::{Deref, DerefMut};
 use ptr::{self, Unique};
-use rt::heap::{allocate, deallocate, EMPTY};
 use collections::hash_state::HashState;
 
+use self::BucketState::*;
+
 const EMPTY_BUCKET: u64 = 0;
 
 /// The raw hashtable, providing safe-ish access to the unzipped and highly
index 5424fec81104b1a372897809d93e247a23edb15e..65667f24dda6c0077ba0ee7ab6a9621a236aed12 100644 (file)
@@ -12,8 +12,8 @@
 
 use cell::Cell;
 use ptr;
-use rt;
 use sync::{StaticMutex, Arc};
+use sys_common;
 
 pub struct Lazy<T> {
     lock: StaticMutex,
@@ -51,7 +51,7 @@ unsafe fn init(&'static self) -> Arc<T> {
         // `Arc` allocation in our own internal box (it will get deallocated by
         // the at exit handler). Otherwise we just return the freshly allocated
         // `Arc`.
-        let registered = rt::at_exit(move || {
+        let registered = sys_common::at_exit(move || {
             let g = self.lock.lock();
             let ptr = self.ptr.get();
             self.ptr.set(1 as *mut _);
index bb4375c1b8826203aa47b35677bacf248c8a500b..9715939d644aa5b61ff258c9c8edf0623c9b82f2 100644 (file)
 
 use any::Any;
 use cell::RefCell;
-use rt::{backtrace, unwind};
 use sys::stdio::Stderr;
+use sys_common::backtrace;
 use sys_common::thread_info;
+use sys_common::unwind;
 
 thread_local! {
     pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
index 79f2d16fef4eee051208ce4ba0bc0679416af969..5f5d5a69003f29e1197dcf46f7953fd127dfe764 100644 (file)
@@ -582,7 +582,7 @@ fn read<T: Read + Send + 'static>(stream: Option<T>) -> Receiver<io::Result<Vec<
 /// to run.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn exit(code: i32) -> ! {
-    ::rt::cleanup();
+    ::sys_common::cleanup();
     ::sys::os::exit(code)
 }
 
diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs
new file mode 100644 (file)
index 0000000..8be0c6f
--- /dev/null
@@ -0,0 +1,65 @@
+// 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 <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.
+
+//! Runtime services
+//!
+//! The `rt` module provides a narrow set of runtime services,
+//! including the global heap (exported in `heap`) and unwinding and
+//! backtrace support. The APIs in this module are highly unstable,
+//! and should be considered as private implementation details for the
+//! time being.
+
+#![unstable(feature = "rt",
+            reason = "this public module should not exist and is highly likely \
+                      to disappear",
+            issue = "0")]
+#![doc(hidden)]
+
+use borrow::ToOwned;
+use mem;
+use sys;
+use sys_common::thread_info::{self, NewThread};
+use sys_common;
+use thread::{self, Thread};
+
+// Reexport some of our utilities which are expected by other crates.
+pub use sys_common::unwind::{begin_unwind, begin_unwind_fmt};
+
+#[cfg(not(test))]
+#[lang = "start"]
+fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
+    sys::init();
+
+    let failed = unsafe {
+        let main_guard = sys::thread::guard::init();
+        sys::stack_overflow::init();
+
+        // Next, set up the current Thread with the guard information we just
+        // created. Note that this isn't necessary in general for new threads,
+        // but we just do this to name the main thread and to give it correct
+        // info about the stack bounds.
+        let thread: Thread = NewThread::new(Some("<main>".to_owned()));
+        thread_info::set(main_guard, thread);
+
+        // Store our args if necessary in a squirreled away location
+        sys_common::args::init(argc, argv);
+
+        // Let's run some code!
+        let res = thread::catch_panic(mem::transmute::<_, fn()>(main));
+        sys_common::cleanup();
+        res.is_err()
+    };
+
+    if failed {
+        101
+    } else {
+        0
+    }
+}
diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs
deleted file mode 100644 (file)
index 8de713a..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2012-2015 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.
-
-//! Global storage for command line arguments
-//!
-//! The current incarnation of the Rust runtime expects for
-//! the processes `argc` and `argv` arguments to be stored
-//! in a globally-accessible location for use by the `os` module.
-//!
-//! Only valid to call on Linux. Mac and Windows use syscalls to
-//! discover the command line arguments.
-//!
-//! FIXME #7756: Would be nice for this to not exist.
-
-use vec::Vec;
-
-/// One-time global initialization.
-pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
-
-/// One-time global cleanup.
-pub unsafe fn cleanup() { imp::cleanup() }
-
-/// Take the global arguments from global storage.
-pub fn take() -> Option<Vec<Vec<u8>>> { imp::take() }
-
-/// Give the global arguments to global storage.
-///
-/// It is an error if the arguments already exist.
-pub fn put(args: Vec<Vec<u8>>) { imp::put(args) }
-
-/// Make a clone of the global arguments.
-pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
-
-#[cfg(any(target_os = "linux",
-          target_os = "android",
-          target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "bitrig",
-          target_os = "netbsd",
-          target_os = "openbsd"))]
-mod imp {
-    use prelude::v1::*;
-
-    use libc;
-    use mem;
-    use ffi::CStr;
-
-    use sync::StaticMutex;
-
-    static mut GLOBAL_ARGS_PTR: usize = 0;
-    static LOCK: StaticMutex = StaticMutex::new();
-
-    pub unsafe fn init(argc: isize, argv: *const *const u8) {
-        let args = load_argc_and_argv(argc, argv);
-        put(args);
-    }
-
-    pub unsafe fn cleanup() {
-        take();
-    }
-
-    pub fn take() -> Option<Vec<Vec<u8>>> {
-        let _guard = LOCK.lock();
-        unsafe {
-            let ptr = get_global_ptr();
-            let val = mem::replace(&mut *ptr, None);
-            val.as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
-        }
-    }
-
-    pub fn put(args: Vec<Vec<u8>>) {
-        let _guard = LOCK.lock();
-        unsafe {
-            let ptr = get_global_ptr();
-            rtassert!((*ptr).is_none());
-            (*ptr) = Some(box args.clone());
-        }
-    }
-
-    pub fn clone() -> Option<Vec<Vec<u8>>> {
-        let _guard = LOCK.lock();
-        unsafe {
-            let ptr = get_global_ptr();
-            (*ptr).as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
-        }
-    }
-
-    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
-        unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
-    }
-
-    unsafe fn load_argc_and_argv(argc: isize,
-                                 argv: *const *const u8) -> Vec<Vec<u8>> {
-        let argv = argv as *const *const libc::c_char;
-        (0..argc).map(|i| {
-            CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec()
-        }).collect()
-    }
-
-    #[cfg(test)]
-    mod tests {
-        use prelude::v1::*;
-
-        use super::*;
-
-        #[test]
-        fn smoke_test() {
-            // Preserve the actual global state.
-            let saved_value = take();
-
-            let expected = vec![
-                b"happy".to_vec(),
-                b"today?".to_vec(),
-            ];
-
-            put(expected.clone());
-            assert!(clone() == Some(expected.clone()));
-            assert!(take() == Some(expected.clone()));
-            assert!(take() == None);
-
-            // Restore the actual global state.
-            match saved_value {
-                Some(ref args) => put(args.clone()),
-                None => ()
-            }
-        }
-    }
-}
-
-#[cfg(any(target_os = "macos",
-          target_os = "ios",
-          target_os = "windows"))]
-mod imp {
-    use vec::Vec;
-
-    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
-    }
-
-    pub fn cleanup() {
-    }
-
-    pub fn take() -> Option<Vec<Vec<u8>>> {
-        panic!()
-    }
-
-    pub fn put(_args: Vec<Vec<u8>>) {
-        panic!()
-    }
-
-    pub fn clone() -> Option<Vec<Vec<u8>>> {
-        panic!()
-    }
-}
diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs
deleted file mode 100644 (file)
index 7a1215b..0000000
+++ /dev/null
@@ -1,82 +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 <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.
-
-//! Implementation of running at_exit routines
-//!
-//! Documentation can be found on the `rt::at_exit` function.
-
-use alloc::boxed::FnBox;
-use boxed::Box;
-use ptr;
-use sys_common::mutex::Mutex;
-use vec::Vec;
-
-type Queue = Vec<Box<FnBox()>>;
-
-// NB these are specifically not types from `std::sync` as they currently rely
-// on poisoning and this module needs to operate at a lower level than requiring
-// the thread infrastructure to be in place (useful on the borders of
-// initialization/destruction).
-static LOCK: Mutex = Mutex::new();
-static mut QUEUE: *mut Queue = ptr::null_mut();
-
-// The maximum number of times the cleanup routines will be run. While running
-// the at_exit closures new ones may be registered, and this count is the number
-// of times the new closures will be allowed to register successfully. After
-// this number of iterations all new registrations will return `false`.
-const ITERS: usize = 10;
-
-unsafe fn init() -> bool {
-    if QUEUE.is_null() {
-        let state: Box<Queue> = box Vec::new();
-        QUEUE = Box::into_raw(state);
-    } else if QUEUE as usize == 1 {
-        // can't re-init after a cleanup
-        return false
-    }
-
-    true
-}
-
-pub fn cleanup() {
-    for i in 0..ITERS {
-        unsafe {
-            LOCK.lock();
-            let queue = QUEUE;
-            QUEUE = if i == ITERS - 1 {1} else {0} as *mut _;
-            LOCK.unlock();
-
-            // make sure we're not recursively cleaning up
-            rtassert!(queue as usize != 1);
-
-            // If we never called init, not need to cleanup!
-            if queue as usize != 0 {
-                let queue: Box<Queue> = Box::from_raw(queue);
-                for to_run in *queue {
-                    to_run();
-                }
-            }
-        }
-    }
-}
-
-pub fn push(f: Box<FnBox()>) -> bool {
-    let mut ret = true;
-    unsafe {
-        LOCK.lock();
-        if init() {
-            (*QUEUE).push(f);
-        } else {
-            ret = false;
-        }
-        LOCK.unlock();
-    }
-    ret
-}
diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs
deleted file mode 100644 (file)
index 9e7ed89..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 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.
-
-//! Simple backtrace functionality (to print on panic)
-
-#![allow(non_camel_case_types)]
-
-use env;
-use sync::atomic::{self, Ordering};
-
-pub use sys::backtrace::write;
-
-// For now logging is turned off by default, and this function checks to see
-// whether the magical environment variable is present to see if it's turned on.
-pub fn log_enabled() -> bool {
-    static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
-    match ENABLED.load(Ordering::SeqCst) {
-        1 => return false,
-        2 => return true,
-        _ => {}
-    }
-
-    let val = match env::var_os("RUST_BACKTRACE") {
-        Some(..) => 2,
-        None => 1,
-    };
-    ENABLED.store(val, Ordering::SeqCst);
-    val == 2
-}
-
-#[cfg(test)]
-mod tests {
-    use prelude::v1::*;
-    use sys_common;
-    macro_rules! t { ($a:expr, $b:expr) => ({
-        let mut m = Vec::new();
-        sys_common::backtrace::demangle(&mut m, $a).unwrap();
-        assert_eq!(String::from_utf8(m).unwrap(), $b);
-    }) }
-
-    #[test]
-    fn demangle() {
-        t!("test", "test");
-        t!("_ZN4testE", "test");
-        t!("_ZN4test", "_ZN4test");
-        t!("_ZN4test1a2bcE", "test::a::bc");
-    }
-
-    #[test]
-    fn demangle_dollars() {
-        t!("_ZN4$RP$E", ")");
-        t!("_ZN8$RF$testE", "&test");
-        t!("_ZN8$BP$test4foobE", "*test::foob");
-        t!("_ZN9$u20$test4foobE", " test::foob");
-    }
-
-    #[test]
-    fn demangle_many_dollars() {
-        t!("_ZN13test$u20$test4foobE", "test test::foob");
-        t!("_ZN12test$BP$test4foobE", "test*test::foob");
-    }
-
-    #[test]
-    fn demangle_windows() {
-        t!("ZN4testE", "test");
-        t!("ZN13test$u20$test4foobE", "test test::foob");
-        t!("ZN12test$RF$test4foobE", "test&test::foob");
-    }
-}
diff --git a/src/libstd/rt/dwarf/eh.rs b/src/libstd/rt/dwarf/eh.rs
deleted file mode 100644 (file)
index f479970..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2015 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.
-
-//! Parsing of GCC-style Language-Specific Data Area (LSDA)
-//! For details see:
-//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
-//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
-//!   http://www.airs.com/blog/archives/460
-//!   http://www.airs.com/blog/archives/464
-//!
-//! A reference implementation may be found in the GCC source tree
-//! (<root>/libgcc/unwind-c.c as of this writing)
-
-#![allow(non_upper_case_globals)]
-#![allow(unused)]
-
-use prelude::v1::*;
-use rt::dwarf::DwarfReader;
-use core::mem;
-
-pub const DW_EH_PE_omit     : u8 = 0xFF;
-pub const DW_EH_PE_absptr   : u8 = 0x00;
-
-pub const DW_EH_PE_uleb128  : u8 = 0x01;
-pub const DW_EH_PE_udata2   : u8 = 0x02;
-pub const DW_EH_PE_udata4   : u8 = 0x03;
-pub const DW_EH_PE_udata8   : u8 = 0x04;
-pub const DW_EH_PE_sleb128  : u8 = 0x09;
-pub const DW_EH_PE_sdata2   : u8 = 0x0A;
-pub const DW_EH_PE_sdata4   : u8 = 0x0B;
-pub const DW_EH_PE_sdata8   : u8 = 0x0C;
-
-pub const DW_EH_PE_pcrel    : u8 = 0x10;
-pub const DW_EH_PE_textrel  : u8 = 0x20;
-pub const DW_EH_PE_datarel  : u8 = 0x30;
-pub const DW_EH_PE_funcrel  : u8 = 0x40;
-pub const DW_EH_PE_aligned  : u8 = 0x50;
-
-pub const DW_EH_PE_indirect : u8 = 0x80;
-
-#[derive(Copy, Clone)]
-pub struct EHContext {
-    pub ip: usize,         // Current instruction pointer
-    pub func_start: usize, // Address of the current function
-    pub text_start: usize, // Address of the code section
-    pub data_start: usize, // Address of the data section
-}
-
-pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext)
-                               -> Option<usize> {
-    if lsda.is_null() {
-        return None;
-    }
-
-    let func_start = context.func_start;
-    let mut reader = DwarfReader::new(lsda);
-
-    let start_encoding = reader.read::<u8>();
-    // base address for landing pad offsets
-    let lpad_base = if start_encoding != DW_EH_PE_omit {
-        read_encoded_pointer(&mut reader, context, start_encoding)
-    } else {
-        func_start
-    };
-
-    let ttype_encoding = reader.read::<u8>();
-    if ttype_encoding != DW_EH_PE_omit {
-        // Rust doesn't analyze exception types, so we don't care about the type table
-        reader.read_uleb128();
-    }
-
-    let call_site_encoding = reader.read::<u8>();
-    let call_site_table_length = reader.read_uleb128();
-    let action_table = reader.ptr.offset(call_site_table_length as isize);
-    // Return addresses point 1 byte past the call instruction, which could
-    // be in the next IP range.
-    let ip = context.ip-1;
-
-    while reader.ptr < action_table {
-        let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_action = reader.read_uleb128();
-        // Callsite table is sorted by cs_start, so if we've passed the ip, we
-        // may stop searching.
-        if ip < func_start + cs_start {
-            break
-        }
-        if ip < func_start + cs_start + cs_len {
-            if cs_lpad != 0 {
-                return Some(lpad_base + cs_lpad);
-            } else {
-                return None;
-            }
-        }
-    }
-    // IP range not found: gcc's C++ personality calls terminate() here,
-    // however the rest of the languages treat this the same as cs_lpad == 0.
-    // We follow this suit.
-    None
-}
-
-#[inline]
-fn round_up(unrounded: usize, align: usize) -> usize {
-    assert!(align.is_power_of_two());
-    (unrounded + align - 1) & !(align - 1)
-}
-
-unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
-                               context: &EHContext,
-                               encoding: u8) -> usize {
-    assert!(encoding != DW_EH_PE_omit);
-
-    // DW_EH_PE_aligned implies it's an absolute pointer value
-    if encoding == DW_EH_PE_aligned {
-        reader.ptr = round_up(reader.ptr as usize,
-                              mem::size_of::<usize>()) as *const u8;
-        return reader.read::<usize>();
-    }
-
-    let mut result = match encoding & 0x0F {
-        DW_EH_PE_absptr => reader.read::<usize>(),
-        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
-        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
-        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
-        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
-        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
-        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
-        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
-        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
-        _ => panic!()
-    };
-
-    result += match encoding & 0x70 {
-        DW_EH_PE_absptr => 0,
-        // relative to address of the encoded value, despite the name
-        DW_EH_PE_pcrel => reader.ptr as usize,
-        DW_EH_PE_textrel => { assert!(context.text_start != 0);
-                              context.text_start },
-        DW_EH_PE_datarel => { assert!(context.data_start != 0);
-                              context.data_start },
-        DW_EH_PE_funcrel => { assert!(context.func_start != 0);
-                              context.func_start },
-        _ => panic!()
-    };
-
-    if encoding & DW_EH_PE_indirect != 0 {
-        result = *(result as *const usize);
-    }
-
-    result
-}
diff --git a/src/libstd/rt/dwarf/mod.rs b/src/libstd/rt/dwarf/mod.rs
deleted file mode 100644 (file)
index 822826b..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2015 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.
-
-//! Utilities for parsing DWARF-encoded data streams.
-//! See http://www.dwarfstd.org,
-//! DWARF-4 standard, Section 7 - "Data Representation"
-
-// This module is used only by x86_64-pc-windows-gnu for now, but we
-// are compiling it everywhere to avoid regressions.
-#![allow(unused)]
-
-pub mod eh;
-
-use prelude::v1::*;
-use core::mem;
-
-pub struct DwarfReader {
-    pub ptr : *const u8
-}
-
-#[repr(C,packed)]
-struct Unaligned<T>(T);
-
-impl DwarfReader {
-
-    pub fn new(ptr : *const u8) -> DwarfReader {
-        DwarfReader {
-            ptr : ptr
-        }
-    }
-
-    // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
-    // on a 4-byte boundary. This may cause problems on platforms with strict
-    // alignment requirements. By wrapping data in a "packed" struct, we are
-    // telling the backend to generate "misalignment-safe" code.
-    pub unsafe fn read<T:Copy>(&mut self) -> T {
-        let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
-        self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
-        result
-    }
-
-    // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
-    // Length Data".
-    pub unsafe fn read_uleb128(&mut self) -> u64 {
-        let mut shift : usize = 0;
-        let mut result : u64 = 0;
-        let mut byte : u8;
-        loop {
-            byte = self.read::<u8>();
-            result |= ((byte & 0x7F) as u64) << shift;
-            shift += 7;
-            if byte & 0x80 == 0 {
-                break;
-            }
-        }
-        result
-    }
-
-    pub unsafe fn read_sleb128(&mut self) -> i64 {
-        let mut shift : usize = 0;
-        let mut result : u64 = 0;
-        let mut byte : u8;
-        loop {
-            byte = self.read::<u8>();
-            result |= ((byte & 0x7F) as u64) << shift;
-            shift += 7;
-            if byte & 0x80 == 0 {
-                break;
-            }
-        }
-        // sign-extend
-        if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
-            result |= (!0 as u64) << shift;
-        }
-        result as i64
-    }
-}
-
-#[test]
-fn dwarf_reader() {
-    let encoded: &[u8] = &[1,
-                           2, 3,
-                           4, 5, 6, 7,
-                           0xE5, 0x8E, 0x26,
-                           0x9B, 0xF1, 0x59,
-                           0xFF, 0xFF];
-
-    let mut reader = DwarfReader::new(encoded.as_ptr());
-
-    unsafe {
-        assert!(reader.read::<u8>() == u8::to_be(1u8));
-        assert!(reader.read::<u16>() == u16::to_be(0x0203));
-        assert!(reader.read::<u32>() == u32::to_be(0x04050607));
-
-        assert!(reader.read_uleb128() == 624485);
-        assert!(reader.read_sleb128() == -624485);
-
-        assert!(reader.read::<i8>() == i8::to_be(-1));
-    }
-}
diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/rt/libunwind.rs
deleted file mode 100644 (file)
index fde6120..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2014-2015 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.
-
-//! Unwind library interface
-
-#![allow(non_upper_case_globals)]
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case)]
-#![allow(dead_code)] // these are just bindings
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-pub use self::_Unwind_Action::*;
-#[cfg(target_arch = "arm")]
-pub use self::_Unwind_State::*;
-pub use self::_Unwind_Reason_Code::*;
-
-use libc;
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum _Unwind_Action {
-    _UA_SEARCH_PHASE = 1,
-    _UA_CLEANUP_PHASE = 2,
-    _UA_HANDLER_FRAME = 4,
-    _UA_FORCE_UNWIND = 8,
-    _UA_END_OF_STACK = 16,
-}
-
-#[cfg(target_arch = "arm")]
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum _Unwind_State {
-    _US_VIRTUAL_UNWIND_FRAME = 0,
-    _US_UNWIND_FRAME_STARTING = 1,
-    _US_UNWIND_FRAME_RESUME = 2,
-    _US_ACTION_MASK = 3,
-    _US_FORCE_UNWIND = 8,
-    _US_END_OF_STACK = 16
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum _Unwind_Reason_Code {
-    _URC_NO_REASON = 0,
-    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
-    _URC_FATAL_PHASE2_ERROR = 2,
-    _URC_FATAL_PHASE1_ERROR = 3,
-    _URC_NORMAL_STOP = 4,
-    _URC_END_OF_STACK = 5,
-    _URC_HANDLER_FOUND = 6,
-    _URC_INSTALL_CONTEXT = 7,
-    _URC_CONTINUE_UNWIND = 8,
-    _URC_FAILURE = 9, // used only by ARM EABI
-}
-
-pub type _Unwind_Exception_Class = u64;
-
-pub type _Unwind_Word = libc::uintptr_t;
-
-#[cfg(target_arch = "x86")]
-pub const unwinder_private_data_size: usize = 5;
-
-#[cfg(target_arch = "x86_64")]
-pub const unwinder_private_data_size: usize = 6;
-
-#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
-pub const unwinder_private_data_size: usize = 20;
-
-#[cfg(all(target_arch = "arm", target_os = "ios"))]
-pub const unwinder_private_data_size: usize = 5;
-
-#[cfg(target_arch = "aarch64")]
-pub const unwinder_private_data_size: usize = 2;
-
-#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
-pub const unwinder_private_data_size: usize = 2;
-
-#[cfg(target_arch = "powerpc")]
-pub const unwinder_private_data_size: usize = 2;
-
-#[repr(C)]
-pub struct _Unwind_Exception {
-    pub exception_class: _Unwind_Exception_Class,
-    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
-    pub private: [_Unwind_Word; unwinder_private_data_size],
-}
-
-pub enum _Unwind_Context {}
-
-pub type _Unwind_Exception_Cleanup_Fn =
-        extern "C" fn(unwind_code: _Unwind_Reason_Code,
-                      exception: *mut _Unwind_Exception);
-
-#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
-          target_os = "freebsd"))]
-#[link(name = "gcc_s")]
-extern {}
-
-#[cfg(all(target_os = "linux", target_env = "musl", not(test)))]
-#[link(name = "unwind", kind = "static")]
-extern {}
-
-#[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))]
-#[link(name = "gcc")]
-extern {}
-
-#[cfg(target_os = "dragonfly")]
-#[link(name = "gcc_pic")]
-extern {}
-
-#[cfg(target_os = "bitrig")]
-#[link(name = "c++abi")]
-extern {}
-
-extern "C" {
-    // iOS on armv7 uses SjLj exceptions and requires to link
-    // against corresponding routine (..._SjLj_...)
-    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
-    pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
-                                  -> _Unwind_Reason_Code;
-
-    #[cfg(all(target_os = "ios", target_arch = "arm"))]
-    fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
-                                   -> _Unwind_Reason_Code;
-
-    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
-}
-
-// ... and now we just providing access to SjLj counterspart
-// through a standard name to hide those details from others
-// (see also comment above regarding _Unwind_RaiseException)
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-#[inline(always)]
-pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
-                                     -> _Unwind_Reason_Code {
-    _Unwind_SjLj_RaiseException(exc)
-}
diff --git a/src/libstd/rt/macros.rs b/src/libstd/rt/macros.rs
deleted file mode 100644 (file)
index 414ccc9..0000000
+++ /dev/null
@@ -1,51 +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.
-
-//! Macros used by the runtime.
-//!
-//! These macros call functions which are only accessible in the `rt` module, so
-//! they aren't defined anywhere outside of the `rt` module.
-
-macro_rules! rterrln {
-    ($fmt:expr) => ( {
-        ::rt::util::dumb_print(format_args!(concat!($fmt, "\n")))
-    } );
-    ($fmt:expr, $($arg:expr),*) => ( {
-        ::rt::util::dumb_print(format_args!(concat!($fmt, "\n"), $($arg),*))
-    } )
-}
-
-// Some basic logging. Enabled by passing `--cfg rtdebug` to the libstd build.
-macro_rules! rtdebug {
-    ($arg:expr) => ( {
-        if cfg!(rtdebug) {
-            rterrln!($arg)
-        }
-    } );
-    ($str:expr, $($arg:expr),*) => ( {
-        if cfg!(rtdebug) {
-            rterrln!($str, $($arg),*)
-        }
-    })
-}
-
-macro_rules! rtassert {
-    ( $arg:expr ) => ( {
-        if ::rt::util::ENFORCE_SANITY {
-            if !$arg {
-                rtabort!(" assertion failed: {}", stringify!($arg));
-            }
-        }
-    } )
-}
-
-macro_rules! rtabort {
-    ($($arg:tt)*) => (::rt::util::abort(format_args!($($arg)*)))
-}
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
deleted file mode 100644 (file)
index 95cba13..0000000
+++ /dev/null
@@ -1,135 +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 <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.
-
-//! Runtime services
-//!
-//! The `rt` module provides a narrow set of runtime services,
-//! including the global heap (exported in `heap`) and unwinding and
-//! backtrace support. The APIs in this module are highly unstable,
-//! and should be considered as private implementation details for the
-//! time being.
-
-#![unstable(feature = "rt",
-            reason = "this public module should not exist and is highly likely \
-                      to disappear",
-            issue = "0")]
-#![allow(missing_docs)]
-
-use prelude::v1::*;
-use sync::Once;
-use sys;
-use thread;
-
-// Reexport some of our utilities which are expected by other crates.
-pub use self::util::min_stack;
-pub use self::unwind::{begin_unwind, begin_unwind_fmt};
-
-// Reexport some functionality from liballoc.
-pub use alloc::heap;
-
-// Simple backtrace functionality (to print on panic)
-pub mod backtrace;
-
-// Internals
-#[macro_use]
-mod macros;
-
-// These should be refactored/moved/made private over time
-pub mod util;
-pub mod unwind;
-pub mod args;
-
-mod at_exit_imp;
-mod libunwind;
-
-mod dwarf;
-
-/// The default error code of the rust runtime if the main thread panics instead
-/// of exiting cleanly.
-pub const DEFAULT_ERROR_CODE: isize = 101;
-
-#[cfg(not(test))]
-#[lang = "start"]
-fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
-    use prelude::v1::*;
-
-    use mem;
-    use rt;
-    use sys_common::thread_info::{self, NewThread};
-    use thread::Thread;
-
-    let failed = unsafe {
-        let main_guard = sys::thread::guard::init();
-        sys::stack_overflow::init();
-
-        // Next, set up the current Thread with the guard information we just
-        // created. Note that this isn't necessary in general for new threads,
-        // but we just do this to name the main thread and to give it correct
-        // info about the stack bounds.
-        let thread: Thread = NewThread::new(Some("<main>".to_owned()));
-        thread_info::set(main_guard, thread);
-
-        // By default, some platforms will send a *signal* when a EPIPE error
-        // would otherwise be delivered. This runtime doesn't install a SIGPIPE
-        // handler, causing it to kill the program, which isn't exactly what we
-        // want!
-        //
-        // Hence, we set SIGPIPE to ignore when the program starts up in order
-        // to prevent this problem.
-        #[cfg(windows)] fn ignore_sigpipe() {}
-        #[cfg(unix)] fn ignore_sigpipe() {
-            use libc;
-            use libc::funcs::posix01::signal::signal;
-            unsafe {
-                assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
-            }
-        }
-        ignore_sigpipe();
-
-        // Store our args if necessary in a squirreled away location
-        args::init(argc, argv);
-
-        // And finally, let's run some code!
-        let res = thread::catch_panic(mem::transmute::<_, fn()>(main));
-        cleanup();
-        res.is_err()
-    };
-
-    // If the exit code wasn't set, then the try block must have panicked.
-    if failed {
-        rt::DEFAULT_ERROR_CODE
-    } else {
-        0
-    }
-}
-
-/// Enqueues a procedure to run when the main thread exits.
-///
-/// Currently these closures are only run once the main *Rust* thread exits.
-/// Once the `at_exit` handlers begin running, more may be enqueued, but not
-/// infinitely so. Eventually a handler registration will be forced to fail.
-///
-/// Returns `Ok` if the handler was successfully registered, meaning that the
-/// closure will be run once the main thread exits. Returns `Err` to indicate
-/// that the closure could not be registered, meaning that it is not scheduled
-/// to be run.
-pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
-    if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
-}
-
-/// One-time runtime cleanup.
-pub fn cleanup() {
-    static CLEANUP: Once = Once::new();
-    CLEANUP.call_once(|| unsafe {
-        args::cleanup();
-        sys::stack_overflow::cleanup();
-        at_exit_imp::cleanup();
-    });
-}
diff --git a/src/libstd/rt/unwind/gcc.rs b/src/libstd/rt/unwind/gcc.rs
deleted file mode 100644 (file)
index 55deb04..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(private_no_mangle_fns)]
-
-use prelude::v1::*;
-
-use any::Any;
-use rt::libunwind as uw;
-
-struct Exception {
-    uwe: uw::_Unwind_Exception,
-    cause: Option<Box<Any + Send + 'static>>,
-}
-
-pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
-    let exception: Box<_> = box Exception {
-        uwe: uw::_Unwind_Exception {
-            exception_class: rust_exception_class(),
-            exception_cleanup: exception_cleanup,
-            private: [0; uw::unwinder_private_data_size],
-        },
-        cause: Some(data),
-    };
-    let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
-    let error = uw::_Unwind_RaiseException(exception_param);
-    rtabort!("Could not unwind stack, error = {}", error as isize);
-
-    extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
-                                exception: *mut uw::_Unwind_Exception) {
-        rtdebug!("exception_cleanup()");
-        unsafe {
-            let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
-        }
-    }
-}
-
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
-    let my_ep = ptr as *mut Exception;
-    rtdebug!("caught {}", (*my_ep).uwe.exception_class);
-    let cause = (*my_ep).cause.take();
-    uw::_Unwind_DeleteException(ptr as *mut _);
-    cause.unwrap()
-}
-
-// Rust's exception class identifier.  This is used by personality routines to
-// determine whether the exception was thrown by their own runtime.
-fn rust_exception_class() -> uw::_Unwind_Exception_Class {
-    // M O Z \0  R U S T -- vendor, language
-    0x4d4f5a_00_52555354
-}
-
-// We could implement our personality routine in pure Rust, however exception
-// info decoding is tedious.  More importantly, personality routines have to
-// handle various platform quirks, which are not fun to maintain.  For this
-// reason, we attempt to reuse personality routine of the C language:
-// __gcc_personality_v0.
-//
-// Since C does not support exception catching, __gcc_personality_v0 simply
-// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
-// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
-//
-// This is pretty close to Rust's exception handling approach, except that Rust
-// does have a single "catch-all" handler at the bottom of each thread's stack.
-// So we have two versions of the personality routine:
-// - rust_eh_personality, used by all cleanup landing pads, which never catches,
-//   so the behavior of __gcc_personality_v0 is perfectly adequate there, and
-// - rust_eh_personality_catch, used only by rust_try(), which always catches.
-//
-// See also: rustc_trans::trans::intrinsic::trans_gnu_try
-
-#[cfg(all(not(target_arch = "arm"),
-          not(all(windows, target_arch = "x86_64")),
-          not(test)))]
-pub mod eabi {
-    use rt::libunwind as uw;
-    use libc::c_int;
-
-    extern {
-        fn __gcc_personality_v0(version: c_int,
-                                actions: uw::_Unwind_Action,
-                                exception_class: uw::_Unwind_Exception_Class,
-                                ue_header: *mut uw::_Unwind_Exception,
-                                context: *mut uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
-    }
-
-    #[lang = "eh_personality"]
-    #[no_mangle]
-    extern fn rust_eh_personality(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_v0(version, actions, exception_class, ue_header,
-                                 context)
-        }
-    }
-
-    #[lang = "eh_personality_catch"]
-    #[no_mangle]
-    pub extern fn rust_eh_personality_catch(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                __gcc_personality_v0(version, actions, exception_class, ue_header,
-                                     context)
-            }
-        }
-    }
-}
-
-// iOS on armv7 is using SjLj exceptions and therefore requires to use
-// a specialized personality routine: __gcc_personality_sj0
-
-#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
-pub mod eabi {
-    use rt::libunwind as uw;
-    use libc::c_int;
-
-    extern {
-        fn __gcc_personality_sj0(version: c_int,
-                                actions: uw::_Unwind_Action,
-                                exception_class: uw::_Unwind_Exception_Class,
-                                ue_header: *mut uw::_Unwind_Exception,
-                                context: *mut uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
-    }
-
-    #[lang = "eh_personality"]
-    #[no_mangle]
-    pub extern fn rust_eh_personality(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_sj0(version, actions, exception_class, ue_header,
-                                  context)
-        }
-    }
-
-    #[lang = "eh_personality_catch"]
-    #[no_mangle]
-    pub extern fn rust_eh_personality_catch(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                __gcc_personality_sj0(version, actions, exception_class, ue_header,
-                                      context)
-            }
-        }
-    }
-}
-
-
-// ARM EHABI uses a slightly different personality routine signature,
-// but otherwise works the same.
-#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
-pub mod eabi {
-    use rt::libunwind as uw;
-    use libc::c_int;
-
-    extern {
-        fn __gcc_personality_v0(state: uw::_Unwind_State,
-                                ue_header: *mut uw::_Unwind_Exception,
-                                context: *mut uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
-    }
-
-    #[lang = "eh_personality"]
-    #[no_mangle]
-    extern fn rust_eh_personality(
-        state: uw::_Unwind_State,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_v0(state, ue_header, context)
-        }
-    }
-
-    #[lang = "eh_personality_catch"]
-    #[no_mangle]
-    pub extern fn rust_eh_personality_catch(
-        state: uw::_Unwind_State,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        if (state as c_int & uw::_US_ACTION_MASK as c_int)
-                           == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                __gcc_personality_v0(state, ue_header, context)
-            }
-        }
-    }
-}
diff --git a/src/libstd/rt/unwind/mod.rs b/src/libstd/rt/unwind/mod.rs
deleted file mode 100644 (file)
index 4feb2d4..0000000
+++ /dev/null
@@ -1,325 +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 <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.
-
-//! Implementation of Rust stack unwinding
-//!
-//! For background on exception handling and stack unwinding please see
-//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
-//! documents linked from it.
-//! These are also good reads:
-//!     http://mentorembedded.github.io/cxx-abi/abi-eh.html
-//!     http://monoinfinito.wordpress.com/series/exception-handling-in-c/
-//!     http://www.airs.com/blog/index.php?s=exception+frames
-//!
-//! ## A brief summary
-//!
-//! Exception handling happens in two phases: a search phase and a cleanup phase.
-//!
-//! In both phases the unwinder walks stack frames from top to bottom using
-//! information from the stack frame unwind sections of the current process's
-//! modules ("module" here refers to an OS module, i.e. an executable or a
-//! dynamic library).
-//!
-//! For each stack frame, it invokes the associated "personality routine", whose
-//! address is also stored in the unwind info section.
-//!
-//! In the search phase, the job of a personality routine is to examine exception
-//! object being thrown, and to decide whether it should be caught at that stack
-//! frame.  Once the handler frame has been identified, cleanup phase begins.
-//!
-//! In the cleanup phase, personality routines invoke cleanup code associated
-//! with their stack frames (i.e. destructors).  Once stack has been unwound down
-//! to the handler frame level, unwinding stops and the last personality routine
-//! transfers control to its catch block.
-//!
-//! ## Frame unwind info registration
-//!
-//! Each module has its own frame unwind info section (usually ".eh_frame"), and
-//! unwinder needs to know about all of them in order for unwinding to be able to
-//! cross module boundaries.
-//!
-//! On some platforms, like Linux, this is achieved by dynamically enumerating
-//! currently loaded modules via the dl_iterate_phdr() API and finding all
-//! .eh_frame sections.
-//!
-//! Others, like Windows, require modules to actively register their unwind info
-//! sections by calling __register_frame_info() API at startup.  In the latter
-//! case it is essential that there is only one copy of the unwinder runtime in
-//! the process.  This is usually achieved by linking to the dynamic version of
-//! the unwind runtime.
-//!
-//! Currently Rust uses unwind runtime provided by libgcc.
-
-#![allow(dead_code)]
-#![allow(unused_imports)]
-
-use prelude::v1::*;
-
-use any::Any;
-use boxed;
-use cell::Cell;
-use cmp;
-use panicking;
-use fmt;
-use intrinsics;
-use mem;
-use sync::atomic::{self, Ordering};
-use sys_common::mutex::Mutex;
-
-// The actual unwinding implementation is cfg'd here, and we've got two current
-// implementations. One goes through SEH on Windows and the other goes through
-// libgcc via the libunwind-like API.
-
-// i686-pc-windows-msvc
-#[cfg(all(windows, target_arch = "x86", target_env = "msvc"))]
-#[path = "seh.rs"] #[doc(hidden)]
-pub mod imp;
-
-// x86_64-pc-windows-*
-#[cfg(all(windows, target_arch = "x86_64"))]
-#[path = "seh64_gnu.rs"] #[doc(hidden)]
-pub mod imp;
-
-// i686-pc-windows-gnu and all others
-#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
-#[path = "gcc.rs"] #[doc(hidden)]
-pub mod imp;
-
-pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32);
-
-// Variables used for invoking callbacks when a thread starts to unwind.
-//
-// For more information, see below.
-const MAX_CALLBACKS: usize = 16;
-static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] =
-        [atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
-         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
-         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
-         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
-         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
-         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
-         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
-         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0)];
-static CALLBACK_CNT: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
-
-thread_local! { static PANICKING: Cell<bool> = Cell::new(false) }
-
-/// Invoke a closure, capturing the cause of panic if one occurs.
-///
-/// This function will return `Ok(())` if the closure did not panic, and will
-/// return `Err(cause)` if the closure panics. The `cause` returned is the
-/// object with which panic was originally invoked.
-///
-/// This function also is unsafe for a variety of reasons:
-///
-/// * This is not safe to call in a nested fashion. The unwinding
-///   interface for Rust is designed to have at most one try/catch block per
-///   thread, not multiple. No runtime checking is currently performed to uphold
-///   this invariant, so this function is not safe. A nested try/catch block
-///   may result in corruption of the outer try/catch block's state, especially
-///   if this is used within a thread itself.
-///
-/// * It is not sound to trigger unwinding while already unwinding. Rust threads
-///   have runtime checks in place to ensure this invariant, but it is not
-///   guaranteed that a rust thread is in place when invoking this function.
-///   Unwinding twice can lead to resource leaks where some destructors are not
-///   run.
-pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
-    let mut f = Some(f);
-    return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);
-
-    // If an inner function were not used here, then this generic function `try`
-    // uses the native symbol `rust_try`, for which the code is statically
-    // linked into the standard library. This means that the DLL for the
-    // standard library must have `rust_try` as an exposed symbol that
-    // downstream crates can link against (because monomorphizations of `try` in
-    // downstream crates will have a reference to the `rust_try` symbol).
-    //
-    // On MSVC this requires the symbol `rust_try` to be tagged with
-    // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
-    // files and instead just have this non-generic shim the compiler can take
-    // care of exposing correctly.
-    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
-                        -> Result<(), Box<Any + Send>> {
-        let prev = PANICKING.with(|s| s.get());
-        PANICKING.with(|s| s.set(false));
-        let ep = intrinsics::try(f, data);
-        PANICKING.with(|s| s.set(prev));
-        if ep.is_null() {
-            Ok(())
-        } else {
-            Err(imp::cleanup(ep))
-        }
-    }
-
-    fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
-        let opt_closure = opt_closure as *mut Option<F>;
-        unsafe { (*opt_closure).take().unwrap()(); }
-    }
-
-    extern {
-        // Rust's try-catch
-        // When f(...) returns normally, the return value is null.
-        // When f(...) throws, the return value is a pointer to the caught
-        // exception object.
-        fn rust_try(f: extern fn(*mut u8),
-                    data: *mut u8) -> *mut u8;
-    }
-}
-
-/// Determines whether the current thread is unwinding because of panic.
-pub fn panicking() -> bool {
-    PANICKING.with(|s| s.get())
-}
-
-// An uninlined, unmangled function upon which to slap yer breakpoints
-#[inline(never)]
-#[no_mangle]
-#[allow(private_no_mangle_fns)]
-fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
-    rtdebug!("begin_unwind()");
-    unsafe {
-        imp::panic(cause)
-    }
-}
-
-#[cfg(not(test))]
-/// Entry point of panic from the libcore crate.
-#[lang = "panic_fmt"]
-pub extern fn rust_begin_unwind(msg: fmt::Arguments,
-                                file: &'static str, line: u32) -> ! {
-    begin_unwind_fmt(msg, &(file, line))
-}
-
-/// The entry point for unwinding with a formatted message.
-///
-/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `panic!()` has as low an impact
-/// on (e.g.) the inlining of other functions as possible), by moving
-/// the actual formatting into this shared place.
-#[inline(never)] #[cold]
-pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
-    use fmt::Write;
-
-    // We do two allocations here, unfortunately. But (a) they're
-    // required with the current scheme, and (b) we don't handle
-    // panic + OOM properly anyway (see comment in begin_unwind
-    // below).
-
-    let mut s = String::new();
-    let _ = s.write_fmt(msg);
-    begin_unwind_inner(Box::new(s), file_line)
-}
-
-/// This is the entry point of unwinding for panic!() and assert!().
-#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
-pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
-    // Note that this should be the only allocation performed in this code path.
-    // Currently this means that panic!() on OOM will invoke this code path,
-    // but then again we're not really ready for panic on OOM anyway. If
-    // we do start doing this, then we should propagate this allocation to
-    // be performed in the parent of this thread instead of the thread that's
-    // panicking.
-
-    // see below for why we do the `Any` coercion here.
-    begin_unwind_inner(Box::new(msg), file_line)
-}
-
-/// The core of the unwinding.
-///
-/// This is non-generic to avoid instantiation bloat in other crates
-/// (which makes compilation of small crates noticeably slower). (Note:
-/// we need the `Any` object anyway, we're not just creating it to
-/// avoid being generic.)
-///
-/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
-/// }` from ~1900/3700 (-O/no opts) to 180/590.
-#[inline(never)] #[cold] // this is the slow path, please never inline this
-fn begin_unwind_inner(msg: Box<Any + Send>,
-                      file_line: &(&'static str, u32)) -> ! {
-    // Make sure the default failure handler is registered before we look at the
-    // callbacks. We also use a raw sys-based mutex here instead of a
-    // `std::sync` one as accessing TLS can cause weird recursive problems (and
-    // we don't need poison checking).
-    unsafe {
-        static LOCK: Mutex = Mutex::new();
-        static mut INIT: bool = false;
-        LOCK.lock();
-        if !INIT {
-            register(panicking::on_panic);
-            INIT = true;
-        }
-        LOCK.unlock();
-    }
-
-    // First, invoke call the user-defined callbacks triggered on thread panic.
-    //
-    // By the time that we see a callback has been registered (by reading
-    // MAX_CALLBACKS), the actual callback itself may have not been stored yet,
-    // so we just chalk it up to a race condition and move on to the next
-    // callback. Additionally, CALLBACK_CNT may briefly be higher than
-    // MAX_CALLBACKS, so we're sure to clamp it as necessary.
-    let callbacks = {
-        let amt = CALLBACK_CNT.load(Ordering::SeqCst);
-        &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)]
-    };
-    for cb in callbacks {
-        match cb.load(Ordering::SeqCst) {
-            0 => {}
-            n => {
-                let f: Callback = unsafe { mem::transmute(n) };
-                let (file, line) = *file_line;
-                f(&*msg, file, line);
-            }
-        }
-    };
-
-    // Now that we've run all the necessary unwind callbacks, we actually
-    // perform the unwinding.
-    if panicking() {
-        // If a thread panics while it's already unwinding then we
-        // have limited options. Currently our preference is to
-        // just abort. In the future we may consider resuming
-        // unwinding or otherwise exiting the thread cleanly.
-        rterrln!("thread panicked while panicking. aborting.");
-        unsafe { intrinsics::abort() }
-    }
-    PANICKING.with(|s| s.set(true));
-    rust_panic(msg);
-}
-
-/// Register a callback to be invoked when a thread unwinds.
-///
-/// This is an unsafe and experimental API which allows for an arbitrary
-/// callback to be invoked when a thread panics. This callback is invoked on both
-/// the initial unwinding and a double unwinding if one occurs. Additionally,
-/// the local `Thread` will be in place for the duration of the callback, and
-/// the callback must ensure that it remains in place once the callback returns.
-///
-/// Only a limited number of callbacks can be registered, and this function
-/// returns whether the callback was successfully registered or not. It is not
-/// currently possible to unregister a callback once it has been registered.
-pub unsafe fn register(f: Callback) -> bool {
-    match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) {
-        // The invocation code has knowledge of this window where the count has
-        // been incremented, but the callback has not been stored. We're
-        // guaranteed that the slot we're storing into is 0.
-        n if n < MAX_CALLBACKS => {
-            let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst);
-            rtassert!(prev == 0);
-            true
-        }
-        // If we accidentally bumped the count too high, pull it back.
-        _ => {
-            CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst);
-            false
-        }
-    }
-}
diff --git a/src/libstd/rt/unwind/seh.rs b/src/libstd/rt/unwind/seh.rs
deleted file mode 100644 (file)
index 8c79375..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2015 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.
-
-//! Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
-//!
-//! On Windows (currently only on MSVC), the default exception handling
-//! mechanism is Structured Exception Handling (SEH). This is quite different
-//! than Dwarf-based exception handling (e.g. what other unix platforms use) in
-//! terms of compiler internals, so LLVM is required to have a good deal of
-//! extra support for SEH. Currently this support is somewhat lacking, so what's
-//! here is the bare bones of SEH support.
-//!
-//! In a nutshell, what happens here is:
-//!
-//! 1. The `panic` function calls the standard Windows function `RaiseException`
-//!    with a Rust-specific code, triggering the unwinding process.
-//! 2. All landing pads generated by the compiler (just "cleanup" landing pads)
-//!    use the personality function `__C_specific_handler`, a function in the
-//!    CRT, and the unwinding code in Windows will use this personality function
-//!    to execute all cleanup code on the stack.
-//! 3. Eventually the "catch" code in `rust_try` (located in
-//!    src/rt/rust_try_msvc_64.ll) is executed, which will ensure that the
-//!    exception being caught is indeed a Rust exception, returning control back
-//!    into Rust.
-//!
-//! Some specific differences from the gcc-based exception handling are:
-//!
-//! * Rust has no custom personality function, it is instead *always*
-//!   __C_specific_handler, so the filtering is done in a C++-like manner
-//!   instead of in the personality function itself. Note that the specific
-//!   syntax for this (found in the rust_try_msvc_64.ll) is taken from an LLVM
-//!   test case for SEH.
-//! * We've got some data to transmit across the unwinding boundary,
-//!   specifically a `Box<Any + Send + 'static>`. In Dwarf-based unwinding this
-//!   data is part of the payload of the exception, but I have not currently
-//!   figured out how to do this with LLVM's bindings. Judging by some comments
-//!   in the LLVM test cases this may not even be possible currently with LLVM,
-//!   so this is just abandoned entirely. Instead the data is stored in a
-//!   thread-local in `panic` and retrieved during `cleanup`.
-//!
-//! So given all that, the bindings here are pretty small,
-
-#![allow(bad_style)]
-
-use prelude::v1::*;
-
-use any::Any;
-use libc::{c_ulong, DWORD, c_void};
-use ptr;
-use sys_common::thread_local::StaticKey;
-
-//                        0x R U S T
-const RUST_PANIC: DWORD = 0x52555354;
-static PANIC_DATA: StaticKey = StaticKey::new(None);
-
-// This function is provided by kernel32.dll
-extern "system" {
-    fn RaiseException(dwExceptionCode: DWORD,
-                      dwExceptionFlags: DWORD,
-                      nNumberOfArguments: DWORD,
-                      lpArguments: *const c_ulong);
-}
-
-#[repr(C)]
-pub struct EXCEPTION_POINTERS {
-    ExceptionRecord: *mut EXCEPTION_RECORD,
-    ContextRecord: *mut CONTEXT,
-}
-
-enum CONTEXT {}
-
-#[repr(C)]
-struct EXCEPTION_RECORD {
-    ExceptionCode: DWORD,
-    ExceptionFlags: DWORD,
-    ExceptionRecord: *mut _EXCEPTION_RECORD,
-    ExceptionAddress: *mut c_void,
-    NumberParameters: DWORD,
-    ExceptionInformation: [*mut c_ulong; EXCEPTION_MAXIMUM_PARAMETERS],
-}
-
-enum _EXCEPTION_RECORD {}
-
-const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
-
-pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
-    // See module docs above for an explanation of why `data` is stored in a
-    // thread local instead of being passed as an argument to the
-    // `RaiseException` function (which can in theory carry along arbitrary
-    // data).
-    let exception = Box::new(data);
-    rtassert!(PANIC_DATA.get().is_null());
-    PANIC_DATA.set(Box::into_raw(exception) as *mut u8);
-
-    RaiseException(RUST_PANIC, 0, 0, ptr::null());
-    rtabort!("could not unwind stack");
-}
-
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
-    // The `ptr` here actually corresponds to the code of the exception, and our
-    // real data is stored in our thread local.
-    rtassert!(ptr as DWORD == RUST_PANIC);
-
-    let data = PANIC_DATA.get() as *mut Box<Any + Send + 'static>;
-    PANIC_DATA.set(ptr::null_mut());
-    rtassert!(!data.is_null());
-
-    *Box::from_raw(data)
-}
-
-// This is required by the compiler to exist (e.g. it's a lang item), but it's
-// never actually called by the compiler because __C_specific_handler is the
-// personality function that is always used. Hence this is just an aborting
-// stub.
-#[lang = "eh_personality"]
-fn rust_eh_personality() {
-    unsafe { ::intrinsics::abort() }
-}
-
-// This is a function referenced from `rust_try_msvc_64.ll` which is used to
-// filter the exceptions being caught by that function.
-//
-// In theory local variables can be accessed through the `rbp` parameter of this
-// function, but a comment in an LLVM test case indicates that this is not
-// implemented in LLVM, so this is just an idempotent function which doesn't
-// ferry along any other information.
-//
-// This function just takes a look at the current EXCEPTION_RECORD being thrown
-// to ensure that it's code is RUST_PANIC, which was set by the call to
-// `RaiseException` above in the `panic` function.
-#[no_mangle]
-#[lang = "msvc_try_filter"]
-pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
-                                _rbp: *mut u8) -> i32 {
-    unsafe {
-        ((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32
-    }
-}
diff --git a/src/libstd/rt/unwind/seh64_gnu.rs b/src/libstd/rt/unwind/seh64_gnu.rs
deleted file mode 100644 (file)
index 78f969b..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2015 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.
-
-//! Unwinding implementation of top of native Win64 SEH,
-//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
-
-#![allow(bad_style)]
-#![allow(private_no_mangle_fns)]
-
-use prelude::v1::*;
-
-use any::Any;
-use self::EXCEPTION_DISPOSITION::*;
-use rt::dwarf::eh;
-use core::mem;
-use core::ptr;
-use libc::{c_void, c_ulonglong, DWORD, LPVOID};
-type ULONG_PTR = c_ulonglong;
-
-// Define our exception codes:
-// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
-//    [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
-//    [29]    = 1 (user-defined)
-//    [28]    = 0 (reserved)
-// we define bits:
-//    [24:27] = type
-//    [0:23]  = magic
-const ETYPE: DWORD = 0b1110_u32 << 28;
-const MAGIC: DWORD = 0x525354; // "RST"
-
-const RUST_PANIC: DWORD  = ETYPE | (1 << 24) | MAGIC;
-
-const EXCEPTION_NONCONTINUABLE: DWORD = 0x1;   // Noncontinuable exception
-const EXCEPTION_UNWINDING: DWORD = 0x2;        // Unwind is in progress
-const EXCEPTION_EXIT_UNWIND: DWORD = 0x4;      // Exit unwind is in progress
-const EXCEPTION_STACK_INVALID: DWORD = 0x8;    // Stack out of limits or unaligned
-const EXCEPTION_NESTED_CALL: DWORD = 0x10;     // Nested exception handler call
-const EXCEPTION_TARGET_UNWIND: DWORD = 0x20;   // Target unwind in progress
-const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call
-const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING |
-                                EXCEPTION_EXIT_UNWIND |
-                                EXCEPTION_TARGET_UNWIND |
-                                EXCEPTION_COLLIDED_UNWIND;
-
-#[repr(C)]
-pub struct EXCEPTION_RECORD {
-    ExceptionCode: DWORD,
-    ExceptionFlags: DWORD,
-    ExceptionRecord: *const EXCEPTION_RECORD,
-    ExceptionAddress: LPVOID,
-    NumberParameters: DWORD,
-    ExceptionInformation: [ULONG_PTR; 15],
-}
-
-pub enum CONTEXT {}
-pub enum UNWIND_HISTORY_TABLE {}
-
-#[repr(C)]
-pub struct RUNTIME_FUNCTION {
-    BeginAddress: DWORD,
-    EndAddress: DWORD,
-    UnwindData: DWORD,
-}
-
-#[repr(C)]
-pub struct DISPATCHER_CONTEXT {
-    ControlPc: LPVOID,
-    ImageBase: LPVOID,
-    FunctionEntry: *const RUNTIME_FUNCTION,
-    EstablisherFrame: LPVOID,
-    TargetIp: LPVOID,
-    ContextRecord: *const CONTEXT,
-    LanguageHandler: LPVOID,
-    HandlerData: *const u8,
-    HistoryTable: *const UNWIND_HISTORY_TABLE,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum EXCEPTION_DISPOSITION {
-    ExceptionContinueExecution,
-    ExceptionContinueSearch,
-    ExceptionNestedException,
-    ExceptionCollidedUnwind
-}
-
-// From kernel32.dll
-extern "system" {
-    fn RaiseException(dwExceptionCode: DWORD,
-                      dwExceptionFlags: DWORD,
-                      nNumberOfArguments: DWORD,
-                      lpArguments: *const ULONG_PTR);
-
-    fn RtlUnwindEx(TargetFrame: LPVOID,
-                   TargetIp: LPVOID,
-                   ExceptionRecord: *const EXCEPTION_RECORD,
-                   ReturnValue: LPVOID,
-                   OriginalContext: *const CONTEXT,
-                   HistoryTable: *const UNWIND_HISTORY_TABLE);
-}
-
-#[repr(C)]
-struct PanicData {
-    data: Box<Any + Send + 'static>
-}
-
-pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
-    let panic_ctx = Box::new(PanicData { data: data });
-    let params = [Box::into_raw(panic_ctx) as ULONG_PTR];
-    rtdebug!("panic: ctx={:X}", params[0]);
-    RaiseException(RUST_PANIC,
-                   EXCEPTION_NONCONTINUABLE,
-                   params.len() as DWORD,
-                   &params as *const ULONG_PTR);
-    rtabort!("could not unwind stack");
-}
-
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
-    rtdebug!("cleanup: ctx={:X}", ptr as usize);
-    let panic_ctx = Box::from_raw(ptr as *mut PanicData);
-    return panic_ctx.data;
-}
-
-// SEH doesn't support resuming unwinds after calling a landing pad like
-// libunwind does. For this reason, MSVC compiler outlines landing pads into
-// separate functions that can be called directly from the personality function
-// but are nevertheless able to find and modify stack frame of the "parent"
-// function.
-//
-// Since this cannot be done with libdwarf-style landing pads,
-// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
-// reraises the exception.
-//
-// Note that it makes certain assumptions about the exception:
-//
-// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
-//    resume execution.
-// 2. That the first parameter of the exception is a pointer to an extra data
-//    area (PanicData).
-// Since these assumptions do not generally hold true for foreign exceptions
-// (system faults, C++ exceptions, etc), we make no attempt to invoke our
-// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
-// This is considered acceptable, because the behavior of throwing exceptions
-// through a C ABI boundary is undefined.
-
-#[lang = "eh_personality_catch"]
-#[cfg(not(test))]
-unsafe extern fn rust_eh_personality_catch(
-    exceptionRecord: *mut EXCEPTION_RECORD,
-    establisherFrame: LPVOID,
-    contextRecord: *mut CONTEXT,
-    dispatcherContext: *mut DISPATCHER_CONTEXT
-) -> EXCEPTION_DISPOSITION
-{
-    rust_eh_personality(exceptionRecord, establisherFrame,
-                        contextRecord, dispatcherContext)
-}
-
-#[lang = "eh_personality"]
-#[cfg(not(test))]
-unsafe extern fn rust_eh_personality(
-    exceptionRecord: *mut EXCEPTION_RECORD,
-    establisherFrame: LPVOID,
-    contextRecord: *mut CONTEXT,
-    dispatcherContext: *mut DISPATCHER_CONTEXT
-) -> EXCEPTION_DISPOSITION
-{
-    let er = &*exceptionRecord;
-    let dc = &*dispatcherContext;
-    rtdebug!("rust_eh_personality: code={:X}, flags={:X}, frame={:X}, ip={:X}",
-        er.ExceptionCode, er.ExceptionFlags,
-        establisherFrame as usize, dc.ControlPc as usize);
-
-    if er.ExceptionFlags & EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
-        if er.ExceptionCode == RUST_PANIC {
-            if let Some(lpad) = find_landing_pad(dc) {
-                rtdebug!("unwinding to landing pad {:X}", lpad);
-
-                RtlUnwindEx(establisherFrame,
-                            lpad as LPVOID,
-                            exceptionRecord,
-                            er.ExceptionInformation[0] as LPVOID, // pointer to PanicData
-                            contextRecord,
-                            dc.HistoryTable);
-                rtabort!("could not unwind");
-            }
-        }
-    }
-    ExceptionContinueSearch
-}
-
-// The `resume` instruction, found at the end of the landing pads, and whose job
-// is to resume stack unwinding, is typically lowered by LLVM into a call to
-// `_Unwind_Resume` routine.  To avoid confusion with the same symbol exported
-// from libgcc, we redirect it to `rust_eh_unwind_resume`.
-// Since resolution of this symbol is done by the linker, `rust_eh_unwind_resume`
-// must be marked `pub` + `#[no_mangle]`.  (Can we make it a lang item?)
-
-#[lang = "eh_unwind_resume"]
-#[cfg(not(test))]
-unsafe extern fn rust_eh_unwind_resume(panic_ctx: LPVOID) {
-    rtdebug!("rust_eh_unwind_resume: ctx={:X}", panic_ctx as usize);
-    let params = [panic_ctx as ULONG_PTR];
-    RaiseException(RUST_PANIC,
-                   EXCEPTION_NONCONTINUABLE,
-                   params.len() as DWORD,
-                   &params as *const ULONG_PTR);
-    rtabort!("could not resume unwind");
-}
-
-unsafe fn find_landing_pad(dc: &DISPATCHER_CONTEXT) -> Option<usize> {
-    let eh_ctx = eh::EHContext {
-        ip: dc.ControlPc as usize,
-        func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
-        text_start: dc.ImageBase as usize,
-        data_start: 0
-    };
-    eh::find_landing_pad(dc.HandlerData, &eh_ctx)
-}
diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs
deleted file mode 100644 (file)
index 23a3c3e..0000000
+++ /dev/null
@@ -1,53 +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 <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 io::prelude::*;
-
-use env;
-use fmt;
-use intrinsics;
-use sync::atomic::{self, Ordering};
-use sys::stdio::Stderr;
-
-pub fn min_stack() -> usize {
-    static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
-    match MIN.load(Ordering::SeqCst) {
-        0 => {}
-        n => return n - 1,
-    }
-    let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
-    let amt = amt.unwrap_or(2 * 1024 * 1024);
-    // 0 is our sentinel value, so ensure that we'll never see 0 after
-    // initialization has run
-    MIN.store(amt + 1, Ordering::SeqCst);
-    amt
-}
-
-// Indicates whether we should perform expensive sanity checks, including rtassert!
-//
-// FIXME: Once the runtime matures remove the `true` below to turn off rtassert,
-//        etc.
-pub const ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) ||
-                                  cfg!(rtassert);
-
-pub fn dumb_print(args: fmt::Arguments) {
-    let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
-}
-
-pub fn abort(args: fmt::Arguments) -> ! {
-    rterrln!("fatal runtime error: {}", args);
-    unsafe { intrinsics::abort(); }
-}
-
-pub unsafe fn report_overflow() {
-    use thread;
-    rterrln!("\nthread '{}' has overflowed its stack",
-             thread::current().name().unwrap_or("<unknown>"));
-}
diff --git a/src/libstd/sys/common/args.rs b/src/libstd/sys/common/args.rs
new file mode 100644 (file)
index 0000000..4cfddb0
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2012-2015 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.
+
+//! Global storage for command line arguments
+//!
+//! The current incarnation of the Rust runtime expects for
+//! the processes `argc` and `argv` arguments to be stored
+//! in a globally-accessible location for use by the `os` module.
+//!
+//! Only valid to call on Linux. Mac and Windows use syscalls to
+//! discover the command line arguments.
+//!
+//! FIXME #7756: Would be nice for this to not exist.
+
+#![allow(dead_code)] // different code on OSX/linux/etc
+
+use vec::Vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Make a clone of the global arguments.
+pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
+
+#[cfg(any(target_os = "linux",
+          target_os = "android",
+          target_os = "freebsd",
+          target_os = "dragonfly",
+          target_os = "bitrig",
+          target_os = "netbsd",
+          target_os = "openbsd"))]
+mod imp {
+    use prelude::v1::*;
+
+    use libc::c_char;
+    use mem;
+    use ffi::CStr;
+
+    use sync::StaticMutex;
+
+    static mut GLOBAL_ARGS_PTR: usize = 0;
+    static LOCK: StaticMutex = StaticMutex::new();
+
+    pub unsafe fn init(argc: isize, argv: *const *const u8) {
+        let args = (0..argc).map(|i| {
+            CStr::from_ptr(*argv.offset(i) as *const c_char).to_bytes().to_vec()
+        }).collect();
+
+        let _guard = LOCK.lock();
+        let ptr = get_global_ptr();
+        assert!((*ptr).is_none());
+        (*ptr) = Some(box args);
+    }
+
+    pub unsafe fn cleanup() {
+        let _guard = LOCK.lock();
+        *get_global_ptr() = None;
+    }
+
+    pub fn clone() -> Option<Vec<Vec<u8>>> {
+        let _guard = LOCK.lock();
+        unsafe {
+            let ptr = get_global_ptr();
+            (*ptr).as_ref().map(|s| (**s).clone())
+        }
+    }
+
+    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+        unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
+    }
+
+}
+
+#[cfg(any(target_os = "macos",
+          target_os = "ios",
+          target_os = "windows"))]
+mod imp {
+    use vec::Vec;
+
+    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+    }
+
+    pub fn cleanup() {
+    }
+
+    pub fn clone() -> Option<Vec<Vec<u8>>> {
+        panic!()
+    }
+}
diff --git a/src/libstd/sys/common/at_exit_imp.rs b/src/libstd/sys/common/at_exit_imp.rs
new file mode 100644 (file)
index 0000000..b268375
--- /dev/null
@@ -0,0 +1,82 @@
+// 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 <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.
+
+//! Implementation of running at_exit routines
+//!
+//! Documentation can be found on the `rt::at_exit` function.
+
+use alloc::boxed::FnBox;
+use boxed::Box;
+use ptr;
+use sys_common::mutex::Mutex;
+use vec::Vec;
+
+type Queue = Vec<Box<FnBox()>>;
+
+// NB these are specifically not types from `std::sync` as they currently rely
+// on poisoning and this module needs to operate at a lower level than requiring
+// the thread infrastructure to be in place (useful on the borders of
+// initialization/destruction).
+static LOCK: Mutex = Mutex::new();
+static mut QUEUE: *mut Queue = ptr::null_mut();
+
+// The maximum number of times the cleanup routines will be run. While running
+// the at_exit closures new ones may be registered, and this count is the number
+// of times the new closures will be allowed to register successfully. After
+// this number of iterations all new registrations will return `false`.
+const ITERS: usize = 10;
+
+unsafe fn init() -> bool {
+    if QUEUE.is_null() {
+        let state: Box<Queue> = box Vec::new();
+        QUEUE = Box::into_raw(state);
+    } else if QUEUE as usize == 1 {
+        // can't re-init after a cleanup
+        return false
+    }
+
+    true
+}
+
+pub fn cleanup() {
+    for i in 0..ITERS {
+        unsafe {
+            LOCK.lock();
+            let queue = QUEUE;
+            QUEUE = if i == ITERS - 1 {1} else {0} as *mut _;
+            LOCK.unlock();
+
+            // make sure we're not recursively cleaning up
+            assert!(queue as usize != 1);
+
+            // If we never called init, not need to cleanup!
+            if queue as usize != 0 {
+                let queue: Box<Queue> = Box::from_raw(queue);
+                for to_run in *queue {
+                    to_run();
+                }
+            }
+        }
+    }
+}
+
+pub fn push(f: Box<FnBox()>) -> bool {
+    let mut ret = true;
+    unsafe {
+        LOCK.lock();
+        if init() {
+            (*QUEUE).push(f);
+        } else {
+            ret = false;
+        }
+        LOCK.unlock();
+    }
+    ret
+}
index 7845714e7f6471acf03b35058faa4e7d698acfb8..e7bda9a7ba2db161426144cf0517f25cc32d38dc 100644 (file)
@@ -8,10 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use io;
+use env;
 use io::prelude::*;
-use str;
+use io;
 use libc;
+use str;
+use sync::atomic::{self, Ordering};
+
+pub use sys::backtrace::write;
 
 #[cfg(target_pointer_width = "64")]
 pub const HEX_WIDTH: usize = 18;
 #[cfg(target_pointer_width = "32")]
 pub const HEX_WIDTH: usize = 10;
 
+// For now logging is turned off by default, and this function checks to see
+// whether the magical environment variable is present to see if it's turned on.
+pub fn log_enabled() -> bool {
+    static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
+    match ENABLED.load(Ordering::SeqCst) {
+        1 => return false,
+        2 => return true,
+        _ => {}
+    }
+
+    let val = match env::var_os("RUST_BACKTRACE") {
+        Some(..) => 2,
+        None => 1,
+    };
+    ENABLED.store(val, Ordering::SeqCst);
+    val == 2
+}
 
 // These output functions should now be used everywhere to ensure consistency.
 pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
@@ -163,3 +184,43 @@ macro_rules! demangle {
 
     Ok(())
 }
+
+#[cfg(test)]
+mod tests {
+    use prelude::v1::*;
+    use sys_common;
+    macro_rules! t { ($a:expr, $b:expr) => ({
+        let mut m = Vec::new();
+        sys_common::backtrace::demangle(&mut m, $a).unwrap();
+        assert_eq!(String::from_utf8(m).unwrap(), $b);
+    }) }
+
+    #[test]
+    fn demangle() {
+        t!("test", "test");
+        t!("_ZN4testE", "test");
+        t!("_ZN4test", "_ZN4test");
+        t!("_ZN4test1a2bcE", "test::a::bc");
+    }
+
+    #[test]
+    fn demangle_dollars() {
+        t!("_ZN4$RP$E", ")");
+        t!("_ZN8$RF$testE", "&test");
+        t!("_ZN8$BP$test4foobE", "*test::foob");
+        t!("_ZN9$u20$test4foobE", " test::foob");
+    }
+
+    #[test]
+    fn demangle_many_dollars() {
+        t!("_ZN13test$u20$test4foobE", "test test::foob");
+        t!("_ZN12test$BP$test4foobE", "test*test::foob");
+    }
+
+    #[test]
+    fn demangle_windows() {
+        t!("ZN4testE", "test");
+        t!("ZN13test$u20$test4foobE", "test test::foob");
+        t!("ZN12test$RF$test4foobE", "test&test::foob");
+    }
+}
diff --git a/src/libstd/sys/common/dwarf/eh.rs b/src/libstd/sys/common/dwarf/eh.rs
new file mode 100644 (file)
index 0000000..319be24
--- /dev/null
@@ -0,0 +1,159 @@
+// Copyright 2015 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.
+
+//! Parsing of GCC-style Language-Specific Data Area (LSDA)
+//! For details see:
+//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
+//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
+//!   http://www.airs.com/blog/archives/460
+//!   http://www.airs.com/blog/archives/464
+//!
+//! A reference implementation may be found in the GCC source tree
+//! (<root>/libgcc/unwind-c.c as of this writing)
+
+#![allow(non_upper_case_globals)]
+#![allow(unused)]
+
+use prelude::v1::*;
+use sys_common::dwarf::DwarfReader;
+use core::mem;
+
+pub const DW_EH_PE_omit     : u8 = 0xFF;
+pub const DW_EH_PE_absptr   : u8 = 0x00;
+
+pub const DW_EH_PE_uleb128  : u8 = 0x01;
+pub const DW_EH_PE_udata2   : u8 = 0x02;
+pub const DW_EH_PE_udata4   : u8 = 0x03;
+pub const DW_EH_PE_udata8   : u8 = 0x04;
+pub const DW_EH_PE_sleb128  : u8 = 0x09;
+pub const DW_EH_PE_sdata2   : u8 = 0x0A;
+pub const DW_EH_PE_sdata4   : u8 = 0x0B;
+pub const DW_EH_PE_sdata8   : u8 = 0x0C;
+
+pub const DW_EH_PE_pcrel    : u8 = 0x10;
+pub const DW_EH_PE_textrel  : u8 = 0x20;
+pub const DW_EH_PE_datarel  : u8 = 0x30;
+pub const DW_EH_PE_funcrel  : u8 = 0x40;
+pub const DW_EH_PE_aligned  : u8 = 0x50;
+
+pub const DW_EH_PE_indirect : u8 = 0x80;
+
+#[derive(Copy, Clone)]
+pub struct EHContext {
+    pub ip: usize,         // Current instruction pointer
+    pub func_start: usize, // Address of the current function
+    pub text_start: usize, // Address of the code section
+    pub data_start: usize, // Address of the data section
+}
+
+pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext)
+                               -> Option<usize> {
+    if lsda.is_null() {
+        return None;
+    }
+
+    let func_start = context.func_start;
+    let mut reader = DwarfReader::new(lsda);
+
+    let start_encoding = reader.read::<u8>();
+    // base address for landing pad offsets
+    let lpad_base = if start_encoding != DW_EH_PE_omit {
+        read_encoded_pointer(&mut reader, context, start_encoding)
+    } else {
+        func_start
+    };
+
+    let ttype_encoding = reader.read::<u8>();
+    if ttype_encoding != DW_EH_PE_omit {
+        // Rust doesn't analyze exception types, so we don't care about the type table
+        reader.read_uleb128();
+    }
+
+    let call_site_encoding = reader.read::<u8>();
+    let call_site_table_length = reader.read_uleb128();
+    let action_table = reader.ptr.offset(call_site_table_length as isize);
+    // Return addresses point 1 byte past the call instruction, which could
+    // be in the next IP range.
+    let ip = context.ip-1;
+
+    while reader.ptr < action_table {
+        let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
+        let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
+        let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
+        let cs_action = reader.read_uleb128();
+        // Callsite table is sorted by cs_start, so if we've passed the ip, we
+        // may stop searching.
+        if ip < func_start + cs_start {
+            break
+        }
+        if ip < func_start + cs_start + cs_len {
+            if cs_lpad != 0 {
+                return Some(lpad_base + cs_lpad);
+            } else {
+                return None;
+            }
+        }
+    }
+    // IP range not found: gcc's C++ personality calls terminate() here,
+    // however the rest of the languages treat this the same as cs_lpad == 0.
+    // We follow this suit.
+    None
+}
+
+#[inline]
+fn round_up(unrounded: usize, align: usize) -> usize {
+    assert!(align.is_power_of_two());
+    (unrounded + align - 1) & !(align - 1)
+}
+
+unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
+                               context: &EHContext,
+                               encoding: u8) -> usize {
+    assert!(encoding != DW_EH_PE_omit);
+
+    // DW_EH_PE_aligned implies it's an absolute pointer value
+    if encoding == DW_EH_PE_aligned {
+        reader.ptr = round_up(reader.ptr as usize,
+                              mem::size_of::<usize>()) as *const u8;
+        return reader.read::<usize>();
+    }
+
+    let mut result = match encoding & 0x0F {
+        DW_EH_PE_absptr => reader.read::<usize>(),
+        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
+        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
+        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
+        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
+        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
+        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
+        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
+        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
+        _ => panic!()
+    };
+
+    result += match encoding & 0x70 {
+        DW_EH_PE_absptr => 0,
+        // relative to address of the encoded value, despite the name
+        DW_EH_PE_pcrel => reader.ptr as usize,
+        DW_EH_PE_textrel => { assert!(context.text_start != 0);
+                              context.text_start },
+        DW_EH_PE_datarel => { assert!(context.data_start != 0);
+                              context.data_start },
+        DW_EH_PE_funcrel => { assert!(context.func_start != 0);
+                              context.func_start },
+        _ => panic!()
+    };
+
+    if encoding & DW_EH_PE_indirect != 0 {
+        result = *(result as *const usize);
+    }
+
+    result
+}
diff --git a/src/libstd/sys/common/dwarf/mod.rs b/src/libstd/sys/common/dwarf/mod.rs
new file mode 100644 (file)
index 0000000..822826b
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright 2015 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.
+
+//! Utilities for parsing DWARF-encoded data streams.
+//! See http://www.dwarfstd.org,
+//! DWARF-4 standard, Section 7 - "Data Representation"
+
+// This module is used only by x86_64-pc-windows-gnu for now, but we
+// are compiling it everywhere to avoid regressions.
+#![allow(unused)]
+
+pub mod eh;
+
+use prelude::v1::*;
+use core::mem;
+
+pub struct DwarfReader {
+    pub ptr : *const u8
+}
+
+#[repr(C,packed)]
+struct Unaligned<T>(T);
+
+impl DwarfReader {
+
+    pub fn new(ptr : *const u8) -> DwarfReader {
+        DwarfReader {
+            ptr : ptr
+        }
+    }
+
+    // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
+    // on a 4-byte boundary. This may cause problems on platforms with strict
+    // alignment requirements. By wrapping data in a "packed" struct, we are
+    // telling the backend to generate "misalignment-safe" code.
+    pub unsafe fn read<T:Copy>(&mut self) -> T {
+        let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
+        self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
+        result
+    }
+
+    // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
+    // Length Data".
+    pub unsafe fn read_uleb128(&mut self) -> u64 {
+        let mut shift : usize = 0;
+        let mut result : u64 = 0;
+        let mut byte : u8;
+        loop {
+            byte = self.read::<u8>();
+            result |= ((byte & 0x7F) as u64) << shift;
+            shift += 7;
+            if byte & 0x80 == 0 {
+                break;
+            }
+        }
+        result
+    }
+
+    pub unsafe fn read_sleb128(&mut self) -> i64 {
+        let mut shift : usize = 0;
+        let mut result : u64 = 0;
+        let mut byte : u8;
+        loop {
+            byte = self.read::<u8>();
+            result |= ((byte & 0x7F) as u64) << shift;
+            shift += 7;
+            if byte & 0x80 == 0 {
+                break;
+            }
+        }
+        // sign-extend
+        if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
+            result |= (!0 as u64) << shift;
+        }
+        result as i64
+    }
+}
+
+#[test]
+fn dwarf_reader() {
+    let encoded: &[u8] = &[1,
+                           2, 3,
+                           4, 5, 6, 7,
+                           0xE5, 0x8E, 0x26,
+                           0x9B, 0xF1, 0x59,
+                           0xFF, 0xFF];
+
+    let mut reader = DwarfReader::new(encoded.as_ptr());
+
+    unsafe {
+        assert!(reader.read::<u8>() == u8::to_be(1u8));
+        assert!(reader.read::<u16>() == u16::to_be(0x0203));
+        assert!(reader.read::<u32>() == u32::to_be(0x04050607));
+
+        assert!(reader.read_uleb128() == 624485);
+        assert!(reader.read_sleb128() == -624485);
+
+        assert!(reader.read::<i8>() == i8::to_be(-1));
+    }
+}
diff --git a/src/libstd/sys/common/libunwind.rs b/src/libstd/sys/common/libunwind.rs
new file mode 100644 (file)
index 0000000..fde6120
--- /dev/null
@@ -0,0 +1,145 @@
+// Copyright 2014-2015 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.
+
+//! Unwind library interface
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)] // these are just bindings
+
+#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
+pub use self::_Unwind_Action::*;
+#[cfg(target_arch = "arm")]
+pub use self::_Unwind_State::*;
+pub use self::_Unwind_Reason_Code::*;
+
+use libc;
+
+#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub enum _Unwind_Action {
+    _UA_SEARCH_PHASE = 1,
+    _UA_CLEANUP_PHASE = 2,
+    _UA_HANDLER_FRAME = 4,
+    _UA_FORCE_UNWIND = 8,
+    _UA_END_OF_STACK = 16,
+}
+
+#[cfg(target_arch = "arm")]
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub enum _Unwind_State {
+    _US_VIRTUAL_UNWIND_FRAME = 0,
+    _US_UNWIND_FRAME_STARTING = 1,
+    _US_UNWIND_FRAME_RESUME = 2,
+    _US_ACTION_MASK = 3,
+    _US_FORCE_UNWIND = 8,
+    _US_END_OF_STACK = 16
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub enum _Unwind_Reason_Code {
+    _URC_NO_REASON = 0,
+    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+    _URC_FATAL_PHASE2_ERROR = 2,
+    _URC_FATAL_PHASE1_ERROR = 3,
+    _URC_NORMAL_STOP = 4,
+    _URC_END_OF_STACK = 5,
+    _URC_HANDLER_FOUND = 6,
+    _URC_INSTALL_CONTEXT = 7,
+    _URC_CONTINUE_UNWIND = 8,
+    _URC_FAILURE = 9, // used only by ARM EABI
+}
+
+pub type _Unwind_Exception_Class = u64;
+
+pub type _Unwind_Word = libc::uintptr_t;
+
+#[cfg(target_arch = "x86")]
+pub const unwinder_private_data_size: usize = 5;
+
+#[cfg(target_arch = "x86_64")]
+pub const unwinder_private_data_size: usize = 6;
+
+#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
+pub const unwinder_private_data_size: usize = 20;
+
+#[cfg(all(target_arch = "arm", target_os = "ios"))]
+pub const unwinder_private_data_size: usize = 5;
+
+#[cfg(target_arch = "aarch64")]
+pub const unwinder_private_data_size: usize = 2;
+
+#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+pub const unwinder_private_data_size: usize = 2;
+
+#[cfg(target_arch = "powerpc")]
+pub const unwinder_private_data_size: usize = 2;
+
+#[repr(C)]
+pub struct _Unwind_Exception {
+    pub exception_class: _Unwind_Exception_Class,
+    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
+    pub private: [_Unwind_Word; unwinder_private_data_size],
+}
+
+pub enum _Unwind_Context {}
+
+pub type _Unwind_Exception_Cleanup_Fn =
+        extern "C" fn(unwind_code: _Unwind_Reason_Code,
+                      exception: *mut _Unwind_Exception);
+
+#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
+          target_os = "freebsd"))]
+#[link(name = "gcc_s")]
+extern {}
+
+#[cfg(all(target_os = "linux", target_env = "musl", not(test)))]
+#[link(name = "unwind", kind = "static")]
+extern {}
+
+#[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))]
+#[link(name = "gcc")]
+extern {}
+
+#[cfg(target_os = "dragonfly")]
+#[link(name = "gcc_pic")]
+extern {}
+
+#[cfg(target_os = "bitrig")]
+#[link(name = "c++abi")]
+extern {}
+
+extern "C" {
+    // iOS on armv7 uses SjLj exceptions and requires to link
+    // against corresponding routine (..._SjLj_...)
+    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
+    pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
+                                  -> _Unwind_Reason_Code;
+
+    #[cfg(all(target_os = "ios", target_arch = "arm"))]
+    fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
+                                   -> _Unwind_Reason_Code;
+
+    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
+}
+
+// ... and now we just providing access to SjLj counterspart
+// through a standard name to hide those details from others
+// (see also comment above regarding _Unwind_RaiseException)
+#[cfg(all(target_os = "ios", target_arch = "arm"))]
+#[inline(always)]
+pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
+                                     -> _Unwind_Reason_Code {
+    _Unwind_SjLj_RaiseException(exc)
+}
index b8074235fb2a5f041e8f1d39b89991a1428e7211..44c55d1e2c45ffcdd019cb363853775889d7dc4a 100644 (file)
 
 #![allow(missing_docs)]
 
+use boxed::Box;
+use sync::Once;
+use sys;
+
+macro_rules! rtabort {
+    ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*)))
+}
+
+macro_rules! rtassert {
+    ($e:expr) => ({
+        if !$e {
+            rtabort!(concat!("assertion failed: ", stringify!($e)))
+        }
+    })
+}
+
+pub mod args;
+pub mod at_exit_imp;
 pub mod backtrace;
 pub mod condvar;
+pub mod dwarf;
+pub mod io;
+pub mod libunwind;
 pub mod mutex;
 pub mod net;
-pub mod io;
 pub mod poison;
 pub mod remutex;
 pub mod rwlock;
 pub mod thread;
 pub mod thread_info;
 pub mod thread_local;
+pub mod unwind;
+pub mod util;
 pub mod wtf8;
 
 #[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios"))),
@@ -52,3 +74,27 @@ pub trait IntoInner<Inner> {
 pub trait FromInner<Inner> {
     fn from_inner(inner: Inner) -> Self;
 }
+
+/// Enqueues a procedure to run when the main thread exits.
+///
+/// Currently these closures are only run once the main *Rust* thread exits.
+/// Once the `at_exit` handlers begin running, more may be enqueued, but not
+/// infinitely so. Eventually a handler registration will be forced to fail.
+///
+/// Returns `Ok` if the handler was successfully registered, meaning that the
+/// closure will be run once the main thread exits. Returns `Err` to indicate
+/// that the closure could not be registered, meaning that it is not scheduled
+/// to be run.
+pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
+    if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
+}
+
+/// One-time runtime cleanup.
+pub fn cleanup() {
+    static CLEANUP: Once = Once::new();
+    CLEANUP.call_once(|| unsafe {
+        args::cleanup();
+        sys::stack_overflow::cleanup();
+        at_exit_imp::cleanup();
+    });
+}
diff --git a/src/libstd/sys/common/unwind/gcc.rs b/src/libstd/sys/common/unwind/gcc.rs
new file mode 100644 (file)
index 0000000..361cef0
--- /dev/null
@@ -0,0 +1,233 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(private_no_mangle_fns)]
+
+use prelude::v1::*;
+
+use any::Any;
+use sys_common::libunwind as uw;
+
+struct Exception {
+    uwe: uw::_Unwind_Exception,
+    cause: Option<Box<Any + Send + 'static>>,
+}
+
+pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
+    let exception: Box<_> = box Exception {
+        uwe: uw::_Unwind_Exception {
+            exception_class: rust_exception_class(),
+            exception_cleanup: exception_cleanup,
+            private: [0; uw::unwinder_private_data_size],
+        },
+        cause: Some(data),
+    };
+    let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
+    let error = uw::_Unwind_RaiseException(exception_param);
+    rtabort!("Could not unwind stack, error = {}", error as isize);
+
+    extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
+                                exception: *mut uw::_Unwind_Exception) {
+        unsafe {
+            let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
+        }
+    }
+}
+
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
+    let my_ep = ptr as *mut Exception;
+    let cause = (*my_ep).cause.take();
+    uw::_Unwind_DeleteException(ptr as *mut _);
+    cause.unwrap()
+}
+
+// Rust's exception class identifier.  This is used by personality routines to
+// determine whether the exception was thrown by their own runtime.
+fn rust_exception_class() -> uw::_Unwind_Exception_Class {
+    // M O Z \0  R U S T -- vendor, language
+    0x4d4f5a_00_52555354
+}
+
+// We could implement our personality routine in pure Rust, however exception
+// info decoding is tedious.  More importantly, personality routines have to
+// handle various platform quirks, which are not fun to maintain.  For this
+// reason, we attempt to reuse personality routine of the C language:
+// __gcc_personality_v0.
+//
+// Since C does not support exception catching, __gcc_personality_v0 simply
+// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
+// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
+//
+// This is pretty close to Rust's exception handling approach, except that Rust
+// does have a single "catch-all" handler at the bottom of each thread's stack.
+// So we have two versions of the personality routine:
+// - rust_eh_personality, used by all cleanup landing pads, which never catches,
+//   so the behavior of __gcc_personality_v0 is perfectly adequate there, and
+// - rust_eh_personality_catch, used only by rust_try(), which always catches.
+//
+// See also: rustc_trans::trans::intrinsic::trans_gnu_try
+
+#[cfg(all(not(target_arch = "arm"),
+          not(all(windows, target_arch = "x86_64")),
+          not(test)))]
+pub mod eabi {
+    use sys_common::libunwind as uw;
+    use libc::c_int;
+
+    extern {
+        fn __gcc_personality_v0(version: c_int,
+                                actions: uw::_Unwind_Action,
+                                exception_class: uw::_Unwind_Exception_Class,
+                                ue_header: *mut uw::_Unwind_Exception,
+                                context: *mut uw::_Unwind_Context)
+            -> uw::_Unwind_Reason_Code;
+    }
+
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    extern fn rust_eh_personality(
+        version: c_int,
+        actions: uw::_Unwind_Action,
+        exception_class: uw::_Unwind_Exception_Class,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        unsafe {
+            __gcc_personality_v0(version, actions, exception_class, ue_header,
+                                 context)
+        }
+    }
+
+    #[lang = "eh_personality_catch"]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
+        version: c_int,
+        actions: uw::_Unwind_Action,
+        exception_class: uw::_Unwind_Exception_Class,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+
+        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+            uw::_URC_HANDLER_FOUND // catch!
+        }
+        else { // cleanup phase
+            unsafe {
+                __gcc_personality_v0(version, actions, exception_class, ue_header,
+                                     context)
+            }
+        }
+    }
+}
+
+// iOS on armv7 is using SjLj exceptions and therefore requires to use
+// a specialized personality routine: __gcc_personality_sj0
+
+#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
+pub mod eabi {
+    use sys_common::libunwind as uw;
+    use libc::c_int;
+
+    extern {
+        fn __gcc_personality_sj0(version: c_int,
+                                actions: uw::_Unwind_Action,
+                                exception_class: uw::_Unwind_Exception_Class,
+                                ue_header: *mut uw::_Unwind_Exception,
+                                context: *mut uw::_Unwind_Context)
+            -> uw::_Unwind_Reason_Code;
+    }
+
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    pub extern fn rust_eh_personality(
+        version: c_int,
+        actions: uw::_Unwind_Action,
+        exception_class: uw::_Unwind_Exception_Class,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        unsafe {
+            __gcc_personality_sj0(version, actions, exception_class, ue_header,
+                                  context)
+        }
+    }
+
+    #[lang = "eh_personality_catch"]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
+        version: c_int,
+        actions: uw::_Unwind_Action,
+        exception_class: uw::_Unwind_Exception_Class,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+            uw::_URC_HANDLER_FOUND // catch!
+        }
+        else { // cleanup phase
+            unsafe {
+                __gcc_personality_sj0(version, actions, exception_class, ue_header,
+                                      context)
+            }
+        }
+    }
+}
+
+
+// ARM EHABI uses a slightly different personality routine signature,
+// but otherwise works the same.
+#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
+pub mod eabi {
+    use sys_common::libunwind as uw;
+    use libc::c_int;
+
+    extern {
+        fn __gcc_personality_v0(state: uw::_Unwind_State,
+                                ue_header: *mut uw::_Unwind_Exception,
+                                context: *mut uw::_Unwind_Context)
+            -> uw::_Unwind_Reason_Code;
+    }
+
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    extern fn rust_eh_personality(
+        state: uw::_Unwind_State,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        unsafe {
+            __gcc_personality_v0(state, ue_header, context)
+        }
+    }
+
+    #[lang = "eh_personality_catch"]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
+        state: uw::_Unwind_State,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        if (state as c_int & uw::_US_ACTION_MASK as c_int)
+                           == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
+            uw::_URC_HANDLER_FOUND // catch!
+        }
+        else { // cleanup phase
+            unsafe {
+                __gcc_personality_v0(state, ue_header, context)
+            }
+        }
+    }
+}
diff --git a/src/libstd/sys/common/unwind/mod.rs b/src/libstd/sys/common/unwind/mod.rs
new file mode 100644 (file)
index 0000000..ff93d05
--- /dev/null
@@ -0,0 +1,325 @@
+// 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 <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.
+
+//! Implementation of Rust stack unwinding
+//!
+//! For background on exception handling and stack unwinding please see
+//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
+//! documents linked from it.
+//! These are also good reads:
+//!     http://mentorembedded.github.io/cxx-abi/abi-eh.html
+//!     http://monoinfinito.wordpress.com/series/exception-handling-in-c/
+//!     http://www.airs.com/blog/index.php?s=exception+frames
+//!
+//! ## A brief summary
+//!
+//! Exception handling happens in two phases: a search phase and a cleanup phase.
+//!
+//! In both phases the unwinder walks stack frames from top to bottom using
+//! information from the stack frame unwind sections of the current process's
+//! modules ("module" here refers to an OS module, i.e. an executable or a
+//! dynamic library).
+//!
+//! For each stack frame, it invokes the associated "personality routine", whose
+//! address is also stored in the unwind info section.
+//!
+//! In the search phase, the job of a personality routine is to examine exception
+//! object being thrown, and to decide whether it should be caught at that stack
+//! frame.  Once the handler frame has been identified, cleanup phase begins.
+//!
+//! In the cleanup phase, personality routines invoke cleanup code associated
+//! with their stack frames (i.e. destructors).  Once stack has been unwound down
+//! to the handler frame level, unwinding stops and the last personality routine
+//! transfers control to its catch block.
+//!
+//! ## Frame unwind info registration
+//!
+//! Each module has its own frame unwind info section (usually ".eh_frame"), and
+//! unwinder needs to know about all of them in order for unwinding to be able to
+//! cross module boundaries.
+//!
+//! On some platforms, like Linux, this is achieved by dynamically enumerating
+//! currently loaded modules via the dl_iterate_phdr() API and finding all
+//! .eh_frame sections.
+//!
+//! Others, like Windows, require modules to actively register their unwind info
+//! sections by calling __register_frame_info() API at startup.  In the latter
+//! case it is essential that there is only one copy of the unwinder runtime in
+//! the process.  This is usually achieved by linking to the dynamic version of
+//! the unwind runtime.
+//!
+//! Currently Rust uses unwind runtime provided by libgcc.
+
+#![allow(dead_code)]
+#![allow(unused_imports)]
+
+use prelude::v1::*;
+
+use any::Any;
+use boxed;
+use cell::Cell;
+use cmp;
+use panicking;
+use fmt;
+use intrinsics;
+use mem;
+use sync::atomic::{self, Ordering};
+use sys_common::mutex::Mutex;
+
+// The actual unwinding implementation is cfg'd here, and we've got two current
+// implementations. One goes through SEH on Windows and the other goes through
+// libgcc via the libunwind-like API.
+
+// i686-pc-windows-msvc
+#[cfg(all(windows, target_arch = "x86", target_env = "msvc"))]
+#[path = "seh.rs"] #[doc(hidden)]
+pub mod imp;
+
+// x86_64-pc-windows-*
+#[cfg(all(windows, target_arch = "x86_64"))]
+#[path = "seh64_gnu.rs"] #[doc(hidden)]
+pub mod imp;
+
+// i686-pc-windows-gnu and all others
+#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
+#[path = "gcc.rs"] #[doc(hidden)]
+pub mod imp;
+
+pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32);
+
+// Variables used for invoking callbacks when a thread starts to unwind.
+//
+// For more information, see below.
+const MAX_CALLBACKS: usize = 16;
+static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] =
+        [atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0)];
+static CALLBACK_CNT: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
+
+thread_local! { static PANICKING: Cell<bool> = Cell::new(false) }
+
+/// Invoke a closure, capturing the cause of panic if one occurs.
+///
+/// This function will return `Ok(())` if the closure did not panic, and will
+/// return `Err(cause)` if the closure panics. The `cause` returned is the
+/// object with which panic was originally invoked.
+///
+/// This function also is unsafe for a variety of reasons:
+///
+/// * This is not safe to call in a nested fashion. The unwinding
+///   interface for Rust is designed to have at most one try/catch block per
+///   thread, not multiple. No runtime checking is currently performed to uphold
+///   this invariant, so this function is not safe. A nested try/catch block
+///   may result in corruption of the outer try/catch block's state, especially
+///   if this is used within a thread itself.
+///
+/// * It is not sound to trigger unwinding while already unwinding. Rust threads
+///   have runtime checks in place to ensure this invariant, but it is not
+///   guaranteed that a rust thread is in place when invoking this function.
+///   Unwinding twice can lead to resource leaks where some destructors are not
+///   run.
+pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
+    let mut f = Some(f);
+    return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);
+
+    // If an inner function were not used here, then this generic function `try`
+    // uses the native symbol `rust_try`, for which the code is statically
+    // linked into the standard library. This means that the DLL for the
+    // standard library must have `rust_try` as an exposed symbol that
+    // downstream crates can link against (because monomorphizations of `try` in
+    // downstream crates will have a reference to the `rust_try` symbol).
+    //
+    // On MSVC this requires the symbol `rust_try` to be tagged with
+    // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
+    // files and instead just have this non-generic shim the compiler can take
+    // care of exposing correctly.
+    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
+                        -> Result<(), Box<Any + Send>> {
+        let prev = PANICKING.with(|s| s.get());
+        PANICKING.with(|s| s.set(false));
+        let ep = intrinsics::try(f, data);
+        PANICKING.with(|s| s.set(prev));
+        if ep.is_null() {
+            Ok(())
+        } else {
+            Err(imp::cleanup(ep))
+        }
+    }
+
+    fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
+        let opt_closure = opt_closure as *mut Option<F>;
+        unsafe { (*opt_closure).take().unwrap()(); }
+    }
+
+    extern {
+        // Rust's try-catch
+        // When f(...) returns normally, the return value is null.
+        // When f(...) throws, the return value is a pointer to the caught
+        // exception object.
+        fn rust_try(f: extern fn(*mut u8),
+                    data: *mut u8) -> *mut u8;
+    }
+}
+
+/// Determines whether the current thread is unwinding because of panic.
+pub fn panicking() -> bool {
+    PANICKING.with(|s| s.get())
+}
+
+// An uninlined, unmangled function upon which to slap yer breakpoints
+#[inline(never)]
+#[no_mangle]
+#[allow(private_no_mangle_fns)]
+fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
+    unsafe {
+        imp::panic(cause)
+    }
+}
+
+#[cfg(not(test))]
+/// Entry point of panic from the libcore crate.
+#[lang = "panic_fmt"]
+pub extern fn rust_begin_unwind(msg: fmt::Arguments,
+                                file: &'static str, line: u32) -> ! {
+    begin_unwind_fmt(msg, &(file, line))
+}
+
+/// The entry point for unwinding with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `panic!()` has as low an impact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
+#[inline(never)] #[cold]
+pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
+    use fmt::Write;
+
+    // We do two allocations here, unfortunately. But (a) they're
+    // required with the current scheme, and (b) we don't handle
+    // panic + OOM properly anyway (see comment in begin_unwind
+    // below).
+
+    let mut s = String::new();
+    let _ = s.write_fmt(msg);
+    begin_unwind_inner(Box::new(s), file_line)
+}
+
+/// This is the entry point of unwinding for panic!() and assert!().
+#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
+pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
+    // Note that this should be the only allocation performed in this code path.
+    // Currently this means that panic!() on OOM will invoke this code path,
+    // but then again we're not really ready for panic on OOM anyway. If
+    // we do start doing this, then we should propagate this allocation to
+    // be performed in the parent of this thread instead of the thread that's
+    // panicking.
+
+    // see below for why we do the `Any` coercion here.
+    begin_unwind_inner(Box::new(msg), file_line)
+}
+
+/// The core of the unwinding.
+///
+/// This is non-generic to avoid instantiation bloat in other crates
+/// (which makes compilation of small crates noticeably slower). (Note:
+/// we need the `Any` object anyway, we're not just creating it to
+/// avoid being generic.)
+///
+/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
+/// }` from ~1900/3700 (-O/no opts) to 180/590.
+#[inline(never)] #[cold] // this is the slow path, please never inline this
+fn begin_unwind_inner(msg: Box<Any + Send>,
+                      file_line: &(&'static str, u32)) -> ! {
+    // Make sure the default failure handler is registered before we look at the
+    // callbacks. We also use a raw sys-based mutex here instead of a
+    // `std::sync` one as accessing TLS can cause weird recursive problems (and
+    // we don't need poison checking).
+    unsafe {
+        static LOCK: Mutex = Mutex::new();
+        static mut INIT: bool = false;
+        LOCK.lock();
+        if !INIT {
+            register(panicking::on_panic);
+            INIT = true;
+        }
+        LOCK.unlock();
+    }
+
+    // First, invoke call the user-defined callbacks triggered on thread panic.
+    //
+    // By the time that we see a callback has been registered (by reading
+    // MAX_CALLBACKS), the actual callback itself may have not been stored yet,
+    // so we just chalk it up to a race condition and move on to the next
+    // callback. Additionally, CALLBACK_CNT may briefly be higher than
+    // MAX_CALLBACKS, so we're sure to clamp it as necessary.
+    let callbacks = {
+        let amt = CALLBACK_CNT.load(Ordering::SeqCst);
+        &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)]
+    };
+    for cb in callbacks {
+        match cb.load(Ordering::SeqCst) {
+            0 => {}
+            n => {
+                let f: Callback = unsafe { mem::transmute(n) };
+                let (file, line) = *file_line;
+                f(&*msg, file, line);
+            }
+        }
+    };
+
+    // Now that we've run all the necessary unwind callbacks, we actually
+    // perform the unwinding.
+    if panicking() {
+        // If a thread panics while it's already unwinding then we
+        // have limited options. Currently our preference is to
+        // just abort. In the future we may consider resuming
+        // unwinding or otherwise exiting the thread cleanly.
+        super::util::dumb_print(format_args!("thread panicked while panicking. \
+                                              aborting."));
+        unsafe { intrinsics::abort() }
+    }
+    PANICKING.with(|s| s.set(true));
+    rust_panic(msg);
+}
+
+/// Register a callback to be invoked when a thread unwinds.
+///
+/// This is an unsafe and experimental API which allows for an arbitrary
+/// callback to be invoked when a thread panics. This callback is invoked on both
+/// the initial unwinding and a double unwinding if one occurs. Additionally,
+/// the local `Thread` will be in place for the duration of the callback, and
+/// the callback must ensure that it remains in place once the callback returns.
+///
+/// Only a limited number of callbacks can be registered, and this function
+/// returns whether the callback was successfully registered or not. It is not
+/// currently possible to unregister a callback once it has been registered.
+pub unsafe fn register(f: Callback) -> bool {
+    match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) {
+        // The invocation code has knowledge of this window where the count has
+        // been incremented, but the callback has not been stored. We're
+        // guaranteed that the slot we're storing into is 0.
+        n if n < MAX_CALLBACKS => {
+            let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst);
+            rtassert!(prev == 0);
+            true
+        }
+        // If we accidentally bumped the count too high, pull it back.
+        _ => {
+            CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst);
+            false
+        }
+    }
+}
diff --git a/src/libstd/sys/common/unwind/seh.rs b/src/libstd/sys/common/unwind/seh.rs
new file mode 100644 (file)
index 0000000..a201e40
--- /dev/null
@@ -0,0 +1,146 @@
+// Copyright 2015 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.
+
+//! Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
+//!
+//! On Windows (currently only on MSVC), the default exception handling
+//! mechanism is Structured Exception Handling (SEH). This is quite different
+//! than Dwarf-based exception handling (e.g. what other unix platforms use) in
+//! terms of compiler internals, so LLVM is required to have a good deal of
+//! extra support for SEH. Currently this support is somewhat lacking, so what's
+//! here is the bare bones of SEH support.
+//!
+//! In a nutshell, what happens here is:
+//!
+//! 1. The `panic` function calls the standard Windows function `RaiseException`
+//!    with a Rust-specific code, triggering the unwinding process.
+//! 2. All landing pads generated by the compiler (just "cleanup" landing pads)
+//!    use the personality function `__C_specific_handler`, a function in the
+//!    CRT, and the unwinding code in Windows will use this personality function
+//!    to execute all cleanup code on the stack.
+//! 3. Eventually the "catch" code in `rust_try` (located in
+//!    src/rt/rust_try_msvc_64.ll) is executed, which will ensure that the
+//!    exception being caught is indeed a Rust exception, returning control back
+//!    into Rust.
+//!
+//! Some specific differences from the gcc-based exception handling are:
+//!
+//! * Rust has no custom personality function, it is instead *always*
+//!   __C_specific_handler, so the filtering is done in a C++-like manner
+//!   instead of in the personality function itself. Note that the specific
+//!   syntax for this (found in the rust_try_msvc_64.ll) is taken from an LLVM
+//!   test case for SEH.
+//! * We've got some data to transmit across the unwinding boundary,
+//!   specifically a `Box<Any + Send + 'static>`. In Dwarf-based unwinding this
+//!   data is part of the payload of the exception, but I have not currently
+//!   figured out how to do this with LLVM's bindings. Judging by some comments
+//!   in the LLVM test cases this may not even be possible currently with LLVM,
+//!   so this is just abandoned entirely. Instead the data is stored in a
+//!   thread-local in `panic` and retrieved during `cleanup`.
+//!
+//! So given all that, the bindings here are pretty small,
+
+#![allow(bad_style)]
+
+use prelude::v1::*;
+
+use any::Any;
+use libc::{c_ulong, DWORD, c_void};
+use ptr;
+use sys_common::thread_local::StaticKey;
+
+//                        0x R U S T
+const RUST_PANIC: DWORD = 0x52555354;
+static PANIC_DATA: StaticKey = StaticKey::new(None);
+
+// This function is provided by kernel32.dll
+extern "system" {
+    fn RaiseException(dwExceptionCode: DWORD,
+                      dwExceptionFlags: DWORD,
+                      nNumberOfArguments: DWORD,
+                      lpArguments: *const c_ulong);
+}
+
+#[repr(C)]
+pub struct EXCEPTION_POINTERS {
+    ExceptionRecord: *mut EXCEPTION_RECORD,
+    ContextRecord: *mut CONTEXT,
+}
+
+enum CONTEXT {}
+
+#[repr(C)]
+struct EXCEPTION_RECORD {
+    ExceptionCode: DWORD,
+    ExceptionFlags: DWORD,
+    ExceptionRecord: *mut _EXCEPTION_RECORD,
+    ExceptionAddress: *mut c_void,
+    NumberParameters: DWORD,
+    ExceptionInformation: [*mut c_ulong; EXCEPTION_MAXIMUM_PARAMETERS],
+}
+
+enum _EXCEPTION_RECORD {}
+
+const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
+
+pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
+    // See module docs above for an explanation of why `data` is stored in a
+    // thread local instead of being passed as an argument to the
+    // `RaiseException` function (which can in theory carry along arbitrary
+    // data).
+    let exception = Box::new(data);
+    rtassert!(PANIC_DATA.get().is_null());
+    PANIC_DATA.set(Box::into_raw(exception) as *mut u8);
+
+    RaiseException(RUST_PANIC, 0, 0, ptr::null());
+    rtabort!("could not unwind stack");
+}
+
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
+    // The `ptr` here actually corresponds to the code of the exception, and our
+    // real data is stored in our thread local.
+    rtassert!(ptr as DWORD == RUST_PANIC);
+
+    let data = PANIC_DATA.get() as *mut Box<Any + Send + 'static>;
+    PANIC_DATA.set(ptr::null_mut());
+    rtassert!(!data.is_null());
+
+    *Box::from_raw(data)
+}
+
+// This is required by the compiler to exist (e.g. it's a lang item), but it's
+// never actually called by the compiler because __C_specific_handler is the
+// personality function that is always used. Hence this is just an aborting
+// stub.
+#[lang = "eh_personality"]
+fn rust_eh_personality() {
+    unsafe { ::intrinsics::abort() }
+}
+
+// This is a function referenced from `rust_try_msvc_64.ll` which is used to
+// filter the exceptions being caught by that function.
+//
+// In theory local variables can be accessed through the `rbp` parameter of this
+// function, but a comment in an LLVM test case indicates that this is not
+// implemented in LLVM, so this is just an idempotent function which doesn't
+// ferry along any other information.
+//
+// This function just takes a look at the current EXCEPTION_RECORD being thrown
+// to ensure that it's code is RUST_PANIC, which was set by the call to
+// `RaiseException` above in the `panic` function.
+#[lang = "msvc_try_filter"]
+#[linkage = "external"]
+#[allow(private_no_mangle_fns)]
+extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
+                            _rbp: *mut u8) -> i32 {
+    unsafe {
+        ((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32
+    }
+}
diff --git a/src/libstd/sys/common/unwind/seh64_gnu.rs b/src/libstd/sys/common/unwind/seh64_gnu.rs
new file mode 100644 (file)
index 0000000..4d23794
--- /dev/null
@@ -0,0 +1,218 @@
+// Copyright 2015 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.
+
+//! Unwinding implementation of top of native Win64 SEH,
+//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
+
+#![allow(bad_style)]
+#![allow(private_no_mangle_fns)]
+
+use prelude::v1::*;
+
+use any::Any;
+use self::EXCEPTION_DISPOSITION::*;
+use sys_common::dwarf::eh;
+use core::mem;
+use core::ptr;
+use libc::{c_void, c_ulonglong, DWORD, LPVOID};
+type ULONG_PTR = c_ulonglong;
+
+// Define our exception codes:
+// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
+//    [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
+//    [29]    = 1 (user-defined)
+//    [28]    = 0 (reserved)
+// we define bits:
+//    [24:27] = type
+//    [0:23]  = magic
+const ETYPE: DWORD = 0b1110_u32 << 28;
+const MAGIC: DWORD = 0x525354; // "RST"
+
+const RUST_PANIC: DWORD  = ETYPE | (1 << 24) | MAGIC;
+
+const EXCEPTION_NONCONTINUABLE: DWORD = 0x1;   // Noncontinuable exception
+const EXCEPTION_UNWINDING: DWORD = 0x2;        // Unwind is in progress
+const EXCEPTION_EXIT_UNWIND: DWORD = 0x4;      // Exit unwind is in progress
+const EXCEPTION_STACK_INVALID: DWORD = 0x8;    // Stack out of limits or unaligned
+const EXCEPTION_NESTED_CALL: DWORD = 0x10;     // Nested exception handler call
+const EXCEPTION_TARGET_UNWIND: DWORD = 0x20;   // Target unwind in progress
+const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call
+const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING |
+                                EXCEPTION_EXIT_UNWIND |
+                                EXCEPTION_TARGET_UNWIND |
+                                EXCEPTION_COLLIDED_UNWIND;
+
+#[repr(C)]
+pub struct EXCEPTION_RECORD {
+    ExceptionCode: DWORD,
+    ExceptionFlags: DWORD,
+    ExceptionRecord: *const EXCEPTION_RECORD,
+    ExceptionAddress: LPVOID,
+    NumberParameters: DWORD,
+    ExceptionInformation: [ULONG_PTR; 15],
+}
+
+pub enum CONTEXT {}
+pub enum UNWIND_HISTORY_TABLE {}
+
+#[repr(C)]
+pub struct RUNTIME_FUNCTION {
+    BeginAddress: DWORD,
+    EndAddress: DWORD,
+    UnwindData: DWORD,
+}
+
+#[repr(C)]
+pub struct DISPATCHER_CONTEXT {
+    ControlPc: LPVOID,
+    ImageBase: LPVOID,
+    FunctionEntry: *const RUNTIME_FUNCTION,
+    EstablisherFrame: LPVOID,
+    TargetIp: LPVOID,
+    ContextRecord: *const CONTEXT,
+    LanguageHandler: LPVOID,
+    HandlerData: *const u8,
+    HistoryTable: *const UNWIND_HISTORY_TABLE,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub enum EXCEPTION_DISPOSITION {
+    ExceptionContinueExecution,
+    ExceptionContinueSearch,
+    ExceptionNestedException,
+    ExceptionCollidedUnwind
+}
+
+// From kernel32.dll
+extern "system" {
+    fn RaiseException(dwExceptionCode: DWORD,
+                      dwExceptionFlags: DWORD,
+                      nNumberOfArguments: DWORD,
+                      lpArguments: *const ULONG_PTR);
+
+    fn RtlUnwindEx(TargetFrame: LPVOID,
+                   TargetIp: LPVOID,
+                   ExceptionRecord: *const EXCEPTION_RECORD,
+                   ReturnValue: LPVOID,
+                   OriginalContext: *const CONTEXT,
+                   HistoryTable: *const UNWIND_HISTORY_TABLE);
+}
+
+#[repr(C)]
+struct PanicData {
+    data: Box<Any + Send + 'static>
+}
+
+pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
+    let panic_ctx = Box::new(PanicData { data: data });
+    let params = [Box::into_raw(panic_ctx) as ULONG_PTR];
+    RaiseException(RUST_PANIC,
+                   EXCEPTION_NONCONTINUABLE,
+                   params.len() as DWORD,
+                   &params as *const ULONG_PTR);
+    rtabort!("could not unwind stack");
+}
+
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
+    let panic_ctx = Box::from_raw(ptr as *mut PanicData);
+    return panic_ctx.data;
+}
+
+// SEH doesn't support resuming unwinds after calling a landing pad like
+// libunwind does. For this reason, MSVC compiler outlines landing pads into
+// separate functions that can be called directly from the personality function
+// but are nevertheless able to find and modify stack frame of the "parent"
+// function.
+//
+// Since this cannot be done with libdwarf-style landing pads,
+// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
+// reraises the exception.
+//
+// Note that it makes certain assumptions about the exception:
+//
+// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
+//    resume execution.
+// 2. That the first parameter of the exception is a pointer to an extra data
+//    area (PanicData).
+// Since these assumptions do not generally hold true for foreign exceptions
+// (system faults, C++ exceptions, etc), we make no attempt to invoke our
+// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
+// This is considered acceptable, because the behavior of throwing exceptions
+// through a C ABI boundary is undefined.
+
+#[lang = "eh_personality_catch"]
+#[cfg(not(test))]
+unsafe extern fn rust_eh_personality_catch(
+    exceptionRecord: *mut EXCEPTION_RECORD,
+    establisherFrame: LPVOID,
+    contextRecord: *mut CONTEXT,
+    dispatcherContext: *mut DISPATCHER_CONTEXT
+) -> EXCEPTION_DISPOSITION
+{
+    rust_eh_personality(exceptionRecord, establisherFrame,
+                        contextRecord, dispatcherContext)
+}
+
+#[lang = "eh_personality"]
+#[cfg(not(test))]
+unsafe extern fn rust_eh_personality(
+    exceptionRecord: *mut EXCEPTION_RECORD,
+    establisherFrame: LPVOID,
+    contextRecord: *mut CONTEXT,
+    dispatcherContext: *mut DISPATCHER_CONTEXT
+) -> EXCEPTION_DISPOSITION
+{
+    let er = &*exceptionRecord;
+    let dc = &*dispatcherContext;
+
+    if er.ExceptionFlags & EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
+        if er.ExceptionCode == RUST_PANIC {
+            if let Some(lpad) = find_landing_pad(dc) {
+                RtlUnwindEx(establisherFrame,
+                            lpad as LPVOID,
+                            exceptionRecord,
+                            er.ExceptionInformation[0] as LPVOID, // pointer to PanicData
+                            contextRecord,
+                            dc.HistoryTable);
+                rtabort!("could not unwind");
+            }
+        }
+    }
+    ExceptionContinueSearch
+}
+
+// The `resume` instruction, found at the end of the landing pads, and whose job
+// is to resume stack unwinding, is typically lowered by LLVM into a call to
+// `_Unwind_Resume` routine.  To avoid confusion with the same symbol exported
+// from libgcc, we redirect it to `rust_eh_unwind_resume`.
+// Since resolution of this symbol is done by the linker, `rust_eh_unwind_resume`
+// must be marked `pub` + `#[no_mangle]`.  (Can we make it a lang item?)
+
+#[lang = "eh_unwind_resume"]
+#[cfg(not(test))]
+unsafe extern fn rust_eh_unwind_resume(panic_ctx: LPVOID) {
+    let params = [panic_ctx as ULONG_PTR];
+    RaiseException(RUST_PANIC,
+                   EXCEPTION_NONCONTINUABLE,
+                   params.len() as DWORD,
+                   &params as *const ULONG_PTR);
+    rtabort!("could not resume unwind");
+}
+
+unsafe fn find_landing_pad(dc: &DISPATCHER_CONTEXT) -> Option<usize> {
+    let eh_ctx = eh::EHContext {
+        ip: dc.ControlPc as usize,
+        func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
+        text_start: dc.ImageBase as usize,
+        data_start: 0
+    };
+    eh::find_landing_pad(dc.HandlerData, &eh_ctx)
+}
diff --git a/src/libstd/sys/common/util.rs b/src/libstd/sys/common/util.rs
new file mode 100644 (file)
index 0000000..979f1f4
--- /dev/null
@@ -0,0 +1,46 @@
+// 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 <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 env;
+use fmt;
+use intrinsics;
+use io::prelude::*;
+use sync::atomic::{self, Ordering};
+use sys::stdio::Stderr;
+use thread;
+
+pub fn min_stack() -> usize {
+    static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
+    match MIN.load(Ordering::SeqCst) {
+        0 => {}
+        n => return n - 1,
+    }
+    let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
+    let amt = amt.unwrap_or(2 * 1024 * 1024);
+    // 0 is our sentinel value, so ensure that we'll never see 0 after
+    // initialization has run
+    MIN.store(amt + 1, Ordering::SeqCst);
+    amt
+}
+
+pub fn dumb_print(args: fmt::Arguments) {
+    let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
+}
+
+pub fn abort(args: fmt::Arguments) -> ! {
+    dumb_print(format_args!("fatal runtime error: {}", args));
+    unsafe { intrinsics::abort(); }
+}
+
+#[allow(dead_code)] // stack overflow detection not enabled on all platforms
+pub unsafe fn report_overflow() {
+    dumb_print(format_args!("\nthread '{}' has overflowed its stack",
+                            thread::current().name().unwrap_or("<unknown>")));
+}
index bbed42cc31d75339a114b76720293e1d16b0f003..964bc08ff4e10b3c835f8a9355923490fad74925 100644 (file)
@@ -12,6 +12,7 @@
 #![allow(non_camel_case_types)]
 
 use io::{self, ErrorKind};
+use libc::funcs::posix01::signal::signal;
 use libc;
 use num::One;
 use ops::Neg;
 pub mod time;
 pub mod stdio;
 
+pub fn init() {
+    // By default, some platforms will send a *signal* when a EPIPE error
+    // would otherwise be delivered. This runtime doesn't install a SIGPIPE
+    // handler, causing it to kill the program, which isn't exactly what we
+    // want!
+    //
+    // Hence, we set SIGPIPE to ignore when the program starts up in order
+    // to prevent this problem.
+    unsafe {
+        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
+    }
+}
+
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
     match errno as libc::c_int {
         libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
index af0d8da05f49ab364d1d5364abc6c96299eef720..94c4d04ea30bbe15192a34e088f1819855910711 100644 (file)
@@ -358,8 +358,8 @@ pub fn args() -> Args {
           target_os = "netbsd",
           target_os = "openbsd"))]
 pub fn args() -> Args {
-    use rt;
-    let bytes = rt::args::clone().unwrap_or(Vec::new());
+    use sys_common;
+    let bytes = sys_common::args::clone().unwrap_or(Vec::new());
     let v: Vec<OsString> = bytes.into_iter().map(|v| {
         OsStringExt::from_vec(v)
     }).collect();
index de9e8cf97e68f6f79b658deb31f9f65f1892066a..441313bc639935dd8046b8510eaa217611e5cc92 100644 (file)
@@ -38,7 +38,7 @@ fn drop(&mut self) {
           target_os = "openbsd"))]
 mod imp {
     use super::Handler;
-    use rt::util::report_overflow;
+    use sys_common::util::report_overflow;
     use mem;
     use ptr;
     use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,
index 732e2e65864fd2a73fe521e626ea3c576a4e3851..04bb5e5ea38331d99f614affc4b7f45cd31354fa 100644 (file)
@@ -43,6 +43,8 @@
 pub mod time;
 pub mod stdio;
 
+pub fn init() {}
+
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
     match errno as libc::c_int {
         libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied,
index e62b2d8cb18ffc01870e43028668f73c0d060f37..998b4fcb1a12114ed2db5af969efa76748b37153 100644 (file)
 use num::One;
 use ops::Neg;
 use ptr;
-use rt;
 use sync::Once;
 use sys;
 use sys::c;
-use sys_common::{AsInner, FromInner, IntoInner};
+use sys_common::{self, AsInner, FromInner, IntoInner};
 use sys_common::net::{setsockopt, getsockopt};
 use time::Duration;
 
@@ -39,7 +38,7 @@ pub fn init() {
                                 &mut data);
         assert_eq!(ret, 0);
 
-        let _ = rt::at_exit(|| { c::WSACleanup(); });
+        let _ = sys_common::at_exit(|| { c::WSACleanup(); });
     });
 }
 
index f93f7c756deff5811005f0394e90d06026bae77d..d1c2144ef0d789152c1bc547a1442772d6520086 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use libc::{self, LONG};
-use rt::util::report_overflow;
+use sys_common::util::report_overflow;
 use sys::c;
 
 pub struct Handler;
index 17bc7ee8876935f077e198e4cd2c3b74c064955a..c544eec7fce85d79b66e838f59a0a57df0dcfb32 100644 (file)
@@ -13,7 +13,7 @@
 use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
 
 use ptr;
-use rt;
+use sys_common;
 use sys_common::mutex::Mutex;
 
 pub type Key = DWORD;
@@ -133,7 +133,7 @@ unsafe fn init_dtors() {
 
     let dtors = box Vec::<(Key, Dtor)>::new();
 
-    let res = rt::at_exit(move|| {
+    let res = sys_common::at_exit(move|| {
         DTOR_LOCK.lock();
         let dtors = DTORS;
         DTORS = 1 as *mut _;
index 3a4c3e7eef1ddc86a0be72d13c51156d9124c370..2b7a3deceb7c4edeea47cd5126cc8163ae2bdb62 100644 (file)
 use cell::UnsafeCell;
 use fmt;
 use io;
-use rt::{self, unwind};
 use sync::{Mutex, Condvar, Arc};
 use sys::thread as imp;
 use sys_common::thread_info;
+use sys_common::unwind;
+use sys_common::util;
 use time::Duration;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -260,7 +261,7 @@ unsafe fn spawn_inner<'a, T: Send>(self, f: Box<FnBox() -> T + Send + 'a>)
                                        -> io::Result<JoinInner<T>> {
         let Builder { name, stack_size } = self;
 
-        let stack_size = stack_size.unwrap_or(rt::min_stack());
+        let stack_size = stack_size.unwrap_or(util::min_stack());
 
         let my_thread = Thread::new(name);
         let their_thread = my_thread.clone();
@@ -383,7 +384,7 @@ pub fn catch_panic<F, R>(f: F) -> Result<R>
     let mut result = None;
     unsafe {
         let result = &mut result;
-        try!(::rt::unwind::try(move || *result = Some(f())))
+        try!(unwind::try(move || *result = Some(f())))
     }
     Ok(result.unwrap())
 }