about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-12-24 12:46:32 -0800
committerbors <bors@rust-lang.org>2013-12-24 12:46:32 -0800
commit32e730f122f06202eb48aefcc2cef6ee3e279a2f (patch)
tree1316fc154599be29d575beb850b1c4ca4a86c24c /src
parentb8c87fd9fe649d3211bb53754fb692a825ecfdff (diff)
parente3b37154b0f321ad74f293d98d9be2ae512c2ec7 (diff)
downloadrust-32e730f122f06202eb48aefcc2cef6ee3e279a2f.tar.gz
rust-32e730f122f06202eb48aefcc2cef6ee3e279a2f.zip
auto merge of #11121 : vadimcn/rust/no-c++2, r=alexcrichton
This PR removes Rust's dependency on C++ for exception handling. Instead, it will use the unwind library API directly.

closes #10469
Diffstat (limited to 'src')
-rw-r--r--src/etc/mklldeps.py1
-rw-r--r--src/librustc/back/link.rs14
-rw-r--r--src/librustc/back/upcall.rs35
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/lib/llvm.rs1
-rw-r--r--src/librustc/middle/lang_items.rs4
-rw-r--r--src/librustc/middle/trans/base.rs11
-rw-r--r--src/librustc/middle/trans/context.rs3
-rw-r--r--src/libstd/rt/mod.rs3
-rw-r--r--src/libstd/rt/task.rs68
-rw-r--r--src/libstd/rt/unwind.rs256
-rw-r--r--src/libstd/rtdeps.rs29
-rw-r--r--src/rt/rust_cxx_glue.cpp31
-rw-r--r--src/rt/rust_try.ll34
-rw-r--r--src/rt/rust_upcall.c3
15 files changed, 343 insertions, 151 deletions
diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py
index 3b2cef3c9e1..5563ad5e7ef 100644
--- a/src/etc/mklldeps.py
+++ b/src/etc/mklldeps.py
@@ -59,6 +59,7 @@ for llconfig in sys.argv[3:]:
     for lib in out.strip().split(' '):
         lib = lib[2:] # chop of the leading '-l'
         f.write("#[link(name = \"" + lib + "\", kind = \"static\")]\n")
+    f.write("#[link(name = \"stdc++\")]\n")
     if os == 'win32':
         f.write("#[link(name = \"imagehlp\")]\n")
     f.write("extern {}\n")
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 9d348ab2dc6..0cf91fbba0e 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -708,10 +708,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
     // In the future, FreeBSD will use clang as default compiler.
     // It would be flexible to use cc (system's default C compiler)
     // instead of hard-coded gcc.
-    // For win32, there is no cc command, so we add a condition to make it use
-    // g++.  We use g++ rather than gcc because it automatically adds linker
-    // options required for generation of dll modules that correctly register
-    // stack unwind tables.
+    // For win32, there is no cc command, so we add a condition to make it use gcc.
     match sess.targ_cfg.os {
         abi::OsAndroid => match sess.opts.android_cross_path {
             Some(ref path) => format!("{}/bin/arm-linux-androideabi-gcc", *path),
@@ -720,7 +717,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
                             (--android-cross-path)")
             }
         },
-        abi::OsWin32 => ~"g++",
+        abi::OsWin32 => ~"gcc",
         _ => ~"cc",
     }
 }
@@ -1032,6 +1029,13 @@ fn link_args(sess: Session,
         }
     }
 
+    if sess.targ_cfg.os == abi::OsWin32 {
+        // Make sure that we link to the dynamic libgcc, otherwise cross-module
+        // DWARF stack unwinding will not work.
+        // This behavior may be overriden by --link-args "-static-libgcc"
+        args.push(~"-shared-libgcc");
+    }
+
     add_local_native_libraries(&mut args, sess);
     add_upstream_rust_crates(&mut args, sess, dylib, tmpdir);
     add_upstream_native_libraries(&mut args, sess);
diff --git a/src/librustc/back/upcall.rs b/src/librustc/back/upcall.rs
deleted file mode 100644
index 730ceba12c7..00000000000
--- a/src/librustc/back/upcall.rs
+++ /dev/null
@@ -1,35 +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.
-
-
-use driver::session;
-use middle::trans::base;
-use middle::trans::type_::Type;
-use lib::llvm::{ModuleRef, ValueRef};
-
-pub struct Upcalls {
-    rust_personality: ValueRef,
-}
-
-macro_rules! upcall (
-    (nothrow fn $name:ident -> $ret:expr) => ({
-        let fn_ty = Type::func([], &$ret);
-        let decl = base::decl_cdecl_fn(llmod, ~"upcall_" + stringify!($name), fn_ty);
-        base::set_no_unwind(decl);
-        decl
-    })
-)
-
-pub fn declare_upcalls(_targ_cfg: @session::config,
-                       llmod: ModuleRef) -> @Upcalls {
-    @Upcalls {
-        rust_personality: upcall!(nothrow fn rust_personality -> Type::i32()),
-    }
-}
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index a516c2b819a..b9f4315ca2b 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -92,7 +92,6 @@ pub mod back {
     pub mod link;
     pub mod manifest;
     pub mod abi;
-    pub mod upcall;
     pub mod arm;
     pub mod mips;
     pub mod x86;
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index 7db4a06e6c0..754b5c8fb08 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -319,7 +319,6 @@ pub mod llvm {
     // automatically updated whenever LLVM is updated to include an up-to-date
     // set of the libraries we need to link to LLVM for.
     #[link(name = "rustllvm", kind = "static")]
-    #[link(name = "stdc++")]
     extern {
         /* Create and destroy contexts. */
         pub fn LLVMContextCreate() -> ContextRef;
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 97b6d10e05d..6fc077876a7 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -208,7 +208,7 @@ pub fn collect_language_items(crate: &ast::Crate,
 }
 
 lets_do_this! {
-    There are 42 lang items.
+    There are 43 lang items.
 
 //  ID, Variant name,                    Name,                      Method name;
     0,  FreezeTraitLangItem,             "freeze",                  freeze_trait;
@@ -261,5 +261,7 @@ lets_do_this! {
     40, EventLoopFactoryLangItem,        "event_loop_factory",      event_loop_factory;
 
     41, TypeIdLangItem,                  "type_id",                 type_id;
+
+    42, EhPersonalityLangItem,           "eh_personality",          eh_personality_fn;
 }
 
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 2f128e59d9d..9d14942a61a 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -37,6 +37,7 @@ use metadata::{csearch, cstore, encoder};
 use middle::astencode;
 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
 use middle::lang_items::{MallocFnLangItem, ClosureExchangeMallocFnLangItem};
+use middle::lang_items::{EhPersonalityLangItem};
 use middle::trans::_match;
 use middle::trans::adt;
 use middle::trans::base;
@@ -1027,10 +1028,10 @@ pub fn get_landing_pad(bcx: @mut Block) -> BasicBlockRef {
     // this represents but it's determined by the personality function and
     // this is what the EH proposal example uses.
     let llretty = Type::struct_([Type::i8p(), Type::i32()], false);
-    // The exception handling personality function. This is the C++
-    // personality function __gxx_personality_v0, wrapped in our naming
-    // convention.
-    let personality = bcx.ccx().upcalls.rust_personality;
+    // The exception handling personality function.
+    let personality = callee::trans_fn_ref(bcx,
+                                           langcall(bcx, None, "", EhPersonalityLangItem),
+                                           0).llfn;
     // The only landing pad clause will be 'cleanup'
     let llretval = LandingPad(pad_bcx, llretty, personality, 1u);
     // The landing pad block is a cleanup
@@ -3195,6 +3196,8 @@ pub fn trans_crate(sess: session::Session,
     reachable.push(ccx.crate_map_name.to_owned());
     reachable.push(~"main");
     reachable.push(~"rust_stack_exhausted");
+    reachable.push(~"rust_eh_personality"); // referenced from .eh_frame section on some platforms
+    reachable.push(~"rust_eh_personality_catch"); // referenced from rt/rust_try.ll
 
     return CrateTranslation {
         context: llcx,
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 167b17ba95c..aca267023c7 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 
-use back::{upcall};
 use driver::session;
 use lib::llvm::{ContextRef, ModuleRef, ValueRef};
 use lib::llvm::{llvm, TargetData, TypeNames};
@@ -105,7 +104,6 @@ pub struct CrateContext {
      tcx: ty::ctxt,
      maps: astencode::Maps,
      stats: @mut Stats,
-     upcalls: @upcall::Upcalls,
      tydesc_type: Type,
      int_type: Type,
      opaque_vec_type: Type,
@@ -233,7 +231,6 @@ impl CrateContext {
                     llvm_insns: HashMap::new(),
                     fn_stats: ~[]
                   },
-                  upcalls: upcall::declare_upcalls(targ_cfg, llmod),
                   tydesc_type: tydesc_type,
                   int_type: int_type,
                   opaque_vec_type: opaque_vec_type,
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 5d2179e8b96..df1ebeb6407 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -173,6 +173,9 @@ mod local_ptr;
 /// Bindings to pthread/windows thread-local storage.
 mod thread_local_storage;
 
+/// Stack unwinding
+pub mod unwind;
+
 /// Just stuff
 mod util;
 
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index 3299caa089a..30e05e9091f 100644
--- a/src/libstd/rt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -18,10 +18,9 @@ use super::local_heap::LocalHeap;
 use prelude::*;
 
 use borrow;
-use cast::transmute;
 use cleanup;
 use io::Writer;
-use libc::{c_void, uintptr_t, c_char, size_t};
+use libc::{c_char, size_t};
 use local_data;
 use option::{Option, Some, None};
 use rt::borrowck::BorrowRecord;
@@ -33,8 +32,8 @@ use rt::local::Local;
 use rt::logging::StdErrLogger;
 use rt::sched::{Scheduler, SchedHandle};
 use rt::stack::{StackSegment, StackPool};
+use rt::unwind::Unwinder;
 use send_str::SendStr;
-use task::TaskResult;
 use unstable::finally::Finally;
 use unstable::mutex::Mutex;
 
@@ -91,21 +90,6 @@ pub enum SchedHome {
 pub struct GarbageCollector;
 pub struct LocalStorage(Option<local_data::Map>);
 
-pub struct Unwinder {
-    unwinding: bool,
-    cause: Option<~Any>
-}
-
-impl Unwinder {
-    fn result(&mut self) -> TaskResult {
-        if self.unwinding {
-            Err(self.cause.take().unwrap())
-        } else {
-            Ok(())
-        }
-    }
-}
-
 impl Task {
 
     // A helper to build a new task using the dynamically found
@@ -452,54 +436,6 @@ impl Coroutine {
 
 }
 
-
-// Just a sanity check to make sure we are catching a Rust-thrown exception
-static UNWIND_TOKEN: uintptr_t = 839147;
-
-impl Unwinder {
-    pub fn try(&mut self, f: ||) {
-        use unstable::raw::Closure;
-
-        unsafe {
-            let closure: Closure = transmute(f);
-            let code = transmute(closure.code);
-            let env = transmute(closure.env);
-
-            let token = rust_try(try_fn, code, env);
-            assert!(token == 0 || token == UNWIND_TOKEN);
-        }
-
-        extern fn try_fn(code: *c_void, env: *c_void) {
-            unsafe {
-                let closure: Closure = Closure {
-                    code: transmute(code),
-                    env: transmute(env),
-                };
-                let closure: || = transmute(closure);
-                closure();
-            }
-        }
-
-        extern {
-            fn rust_try(f: extern "C" fn(*c_void, *c_void),
-                        code: *c_void,
-                        data: *c_void) -> uintptr_t;
-        }
-    }
-
-    pub fn begin_unwind(&mut self, cause: ~Any) -> ! {
-        self.unwinding = true;
-        self.cause = Some(cause);
-        unsafe {
-            rust_begin_unwind(UNWIND_TOKEN);
-            return transmute(());
-        }
-        extern {
-            fn rust_begin_unwind(token: uintptr_t);
-        }
-    }
-}
-
 /// This function is invoked from rust's current __morestack function. Segmented
 /// stacks are currently not enabled as segmented stacks, but rather one giant
 /// stack segment. This means that whenever we run out of stack, we want to
diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs
new file mode 100644
index 00000000000..3f6f54a9c0e
--- /dev/null
+++ b/src/libstd/rt/unwind.rs
@@ -0,0 +1,256 @@
+// 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://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
+//     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.
+
+use prelude::*;
+use cast::transmute;
+use task::TaskResult;
+use libc::{c_void, c_int};
+use self::libunwind::*;
+
+mod libunwind {
+    //! Unwind library interface
+
+    #[allow(non_camel_case_types)];
+
+    use libc::{uintptr_t, uint64_t};
+
+    #[repr(C)]
+    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,
+    }
+
+    #[repr(C)]
+    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,
+    }
+
+    pub type _Unwind_Exception_Class = uint64_t;
+
+    pub type _Unwind_Word = uintptr_t;
+
+    pub struct _Unwind_Exception {
+        exception_class: _Unwind_Exception_Class,
+        exception_cleanup: _Unwind_Exception_Cleanup_Fn,
+        private_1: _Unwind_Word,
+        private_2: _Unwind_Word,
+    }
+
+    pub enum _Unwind_Context {}
+
+    pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code,
+                                                          exception: *_Unwind_Exception);
+
+    extern "C" {
+        pub fn _Unwind_RaiseException(exception: *_Unwind_Exception) -> _Unwind_Reason_Code;
+        pub fn _Unwind_DeleteException(exception: *_Unwind_Exception);
+    }
+}
+
+pub struct Unwinder {
+    unwinding: bool,
+    cause: Option<~Any>
+}
+
+impl Unwinder {
+
+    pub fn try(&mut self, f: ||) {
+        use unstable::raw::Closure;
+
+        unsafe {
+            let closure: Closure = transmute(f);
+            let code = transmute(closure.code);
+            let env = transmute(closure.env);
+
+            let ep = rust_try(try_fn, code, env);
+            if !ep.is_null() {
+                rtdebug!("Caught {}", (*ep).exception_class);
+                _Unwind_DeleteException(ep);
+            }
+        }
+
+        extern fn try_fn(code: *c_void, env: *c_void) {
+            unsafe {
+                let closure: Closure = Closure {
+                    code: transmute(code),
+                    env: transmute(env),
+                };
+                let closure: || = transmute(closure);
+                closure();
+            }
+        }
+
+        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 "C" fn(*c_void, *c_void),
+                        code: *c_void,
+                        data: *c_void) -> *_Unwind_Exception;
+        }
+    }
+
+    pub fn begin_unwind(&mut self, cause: ~Any) -> ! {
+        rtdebug!("begin_unwind()");
+
+        self.unwinding = true;
+        self.cause = Some(cause);
+
+        unsafe {
+            let exception = ~_Unwind_Exception {
+                exception_class: rust_exception_class(),
+                exception_cleanup: exception_cleanup,
+                private_1: 0,
+                private_2: 0
+            };
+            let error = _Unwind_RaiseException(transmute(exception));
+            rtabort!("Could not unwind stack, error = {}", error as int)
+        }
+
+        extern "C" fn exception_cleanup(_unwind_code: _Unwind_Reason_Code,
+                                        exception: *_Unwind_Exception) {
+            rtdebug!("exception_cleanup()");
+            unsafe {
+                let _: ~_Unwind_Exception = transmute(exception);
+            }
+        }
+    }
+
+    pub fn result(&mut self) -> TaskResult {
+        if self.unwinding {
+            Err(self.cause.take().unwrap())
+        } else {
+            Ok(())
+        }
+    }
+}
+
+// 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() -> _Unwind_Exception_Class {
+    let bytes = bytes!("MOZ\0RUST"); // vendor, language
+    unsafe {
+        let ptr: *_Unwind_Exception_Class = transmute(bytes.as_ptr());
+        *ptr
+    }
+}
+
+
+// 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 task's stack.
+// So we have two versions:
+// - 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.  This is
+//   achieved by overriding the return value in search phase to always say "catch!".
+
+extern "C" {
+    fn __gcc_personality_v0(version: c_int,
+                            actions: _Unwind_Action,
+                            exception_class: _Unwind_Exception_Class,
+                            ue_header: *_Unwind_Exception,
+                            context: *_Unwind_Context) -> _Unwind_Reason_Code;
+}
+
+#[lang="eh_personality"]
+#[no_mangle] // so we can reference it by name from middle/trans/base.rs
+#[doc(hidden)]
+#[cfg(not(test))]
+pub extern "C" fn rust_eh_personality(version: c_int,
+                                      actions: _Unwind_Action,
+                                      exception_class: _Unwind_Exception_Class,
+                                      ue_header: *_Unwind_Exception,
+                                      context: *_Unwind_Context) -> _Unwind_Reason_Code {
+    unsafe {
+        __gcc_personality_v0(version, actions, exception_class, ue_header, context)
+    }
+}
+
+#[no_mangle] // referenced from rust_try.ll
+#[doc(hidden)]
+#[cfg(not(test))]
+pub extern "C" fn rust_eh_personality_catch(version: c_int,
+                                            actions: _Unwind_Action,
+                                            exception_class: _Unwind_Exception_Class,
+                                            ue_header: *_Unwind_Exception,
+                                            context: *_Unwind_Context) -> _Unwind_Reason_Code {
+    if (actions as c_int & _UA_SEARCH_PHASE as c_int) != 0 { // search phase
+        _URC_HANDLER_FOUND // catch!
+    }
+    else { // cleanup phase
+        unsafe {
+             __gcc_personality_v0(version, actions, exception_class, ue_header, context)
+        }
+    }
+}
diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs
index 1d13670366c..01d163f49e0 100644
--- a/src/libstd/rtdeps.rs
+++ b/src/libstd/rtdeps.rs
@@ -26,24 +26,45 @@ extern {}
 #[link(name = "dl")]
 #[link(name = "m")]
 #[link(name = "pthread")]
-#[link(name = "stdc++")]
 extern {}
 
 #[cfg(target_os = "android")]
 #[link(name = "dl")]
 #[link(name = "log")]
-#[link(name = "supc++")]
 #[link(name = "m")]
 extern {}
 
 #[cfg(target_os = "freebsd")]
 #[link(name = "execinfo")]
 #[link(name = "rt")]
-#[link(name = "stdc++")]
 #[link(name = "pthread")]
 extern {}
 
 #[cfg(target_os = "macos")]
 #[link(name = "pthread")]
-#[link(name = "stdc++")]
 extern {}
+
+// NOTE: remove after snapshot
+// stage0-generated code still depends on c++
+#[cfg(stage0)]
+mod stage0 {
+    #[cfg(target_os = "linux")]
+    #[link(name = "stdc++")]
+    extern {}
+
+    #[cfg(target_os = "android")]
+    #[link(name = "supc++")]
+    extern {}
+
+    #[cfg(target_os = "freebsd")]
+    #[link(name = "stdc++")]
+    extern {}
+
+    #[cfg(target_os = "macos")]
+    #[link(name = "stdc++")]
+    extern {}
+
+    #[cfg(target_os = "win32")]
+    #[link(name = "stdc++")]
+    extern {}
+}
diff --git a/src/rt/rust_cxx_glue.cpp b/src/rt/rust_cxx_glue.cpp
deleted file mode 100644
index b44d29642c4..00000000000
--- a/src/rt/rust_cxx_glue.cpp
+++ /dev/null
@@ -1,31 +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.
-
-/* Foreign builtins which require C++ */
-
-#include "rust_globals.h"
-
-typedef void *(rust_try_fn)(void*, void*);
-
-extern "C" CDECL uintptr_t
-rust_try(rust_try_fn f, void *fptr, void *env) {
-    try {
-        f(fptr, env);
-    } catch (uintptr_t token) {
-        assert(token != 0);
-        return token;
-    }
-    return 0;
-}
-
-extern "C" CDECL void
-rust_begin_unwind(uintptr_t token) {
-    throw token;
-}
diff --git a/src/rt/rust_try.ll b/src/rt/rust_try.ll
new file mode 100644
index 00000000000..c912aa789bf
--- /dev/null
+++ b/src/rt/rust_try.ll
@@ -0,0 +1,34 @@
+; 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.
+
+; 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.
+; See also: libstd/rt/unwind.rs
+
+define i8* @rust_try(void (i8*,i8*)* %f, i8* %fptr, i8* %env) {
+
+	invoke void %f(i8* %fptr, i8* %env)
+		to label %normal
+		unwind label %catch
+
+normal:
+	ret i8* null
+
+catch:
+	%1 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @rust_eh_personality_catch to i8*)
+			catch i8* null ; catch everything
+
+	; extract and return pointer to the exception object
+    %2 = extractvalue { i8*, i32 } %1, 0
+	ret i8* %2
+}
+
+declare i32 @rust_eh_personality_catch(...)
diff --git a/src/rt/rust_upcall.c b/src/rt/rust_upcall.c
index 6a3e7b7513c..daa46bab404 100644
--- a/src/rt/rust_upcall.c
+++ b/src/rt/rust_upcall.c
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// NOTE: remove this file after snapshot
+// unwind personality routine lives now in libstd/rt/unwind.rs
+
 /*
   Upcalls