diff --git a/mk/rt.mk b/mk/rt.mk index 7c33759ed8108..6d5e4ae2fef44 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -72,9 +72,6 @@ RUNTIME_CXXFLAGS_$(1)_$(2) = -D_RUST_STAGE1 endif endif -RUNTIME_CXXS_$(1)_$(2) := \ - rt/rust_cxx_glue.cpp - RUNTIME_CS_$(1)_$(2) := \ rt/rust_builtin.c \ rt/rust_upcall.c \ @@ -82,6 +79,9 @@ RUNTIME_CS_$(1)_$(2) := \ rt/rust_android_dummy.c \ rt/rust_test_helpers.c +RUNTIME_LL_$(1)_$(2) := \ + rt/rust_try.ll + # stage0 remove this after the next snapshot %.cpp: @touch tmp/foo.o @@ -94,19 +94,16 @@ RT_BUILD_DIR_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/stage$(2) RUNTIME_DEF_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/rustrt$$(CFG_DEF_SUFFIX_$(1)) RUNTIME_INCS_$(1)_$(2) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \ -I $$(S)src/rt/arch/$$(HOST_$(1)) -RUNTIME_OBJS_$(1)_$(2) := $$(RUNTIME_CXXS_$(1)_$(2):rt/%.cpp=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \ +RUNTIME_OBJS_$(1)_$(2) := \ $$(RUNTIME_CS_$(1)_$(2):rt/%.c=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \ - $$(RUNTIME_S_$(1)_$(2):rt/%.S=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) + $$(RUNTIME_S_$(1)_$(2):rt/%.S=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \ + $$(RUNTIME_LL_$(1)_$(2):rt/%.ll=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) + ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1)_$(2)) MORESTACK_OBJS_$(1)_$(2) := $$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/morestack.o ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1)_$(2)) -$$(RT_BUILD_DIR_$(1)_$(2))/rust_cxx_glue.o: rt/rust_cxx_glue.cpp $$(MKFILE_DEPS) - @$$(call E, compile: $$@) - $$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \ - $$(SNAP_DEFINES) $$(RUNTIME_CXXFLAGS_$(1)_$(2))) $$< - $$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.c $$(MKFILE_DEPS) @$$(call E, compile: $$@) $$(Q)$$(call CFG_COMPILE_C_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \ @@ -117,6 +114,11 @@ $$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.S $$(MKFILE_DEPS) \ @$$(call E, compile: $$@) $$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<) +$$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.ll $$(MKFILE_DEPS) \ + $$(LLVM_CONFIG_$$(CFG_BUILD)) + @$$(call E, compile: $$@) + $$(Q)$(LLC_$(CFG_BUILD)) -filetype=obj -mtriple=$(1) -relocation-model=pic -o $$@ $$< + $$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/libmorestack.a: $$(MORESTACK_OBJS_$(1)_$(2)) @$$(call E, link: $$@) $$(Q)$(AR_$(1)) rcs $$@ $$^ diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 3b2cef3c9e1cb..5563ad5e7ef2d 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -59,6 +59,7 @@ 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 9d348ab2dc653..0cf91fbba0e88 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 730ceba12c786..0000000000000 --- 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 or the MIT license -// , 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 a516c2b819adc..b9f4315ca2b13 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 7db4a06e6c02b..754b5c8fb0807 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 97b6d10e05d0a..6fc077876a70d 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 2f128e59d9dca..9d14942a61ab0 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 167b17ba95c6c..aca267023c7e9 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 5d2179e8b9693..df1ebeb6407aa 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 3299caa089aba..30e05e9091f3e 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); -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 0000000000000..3f6f54a9c0eee --- /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 or the MIT license +// , 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 1d13670366c10..01d163f49e0a3 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 b44d29642c4b7..0000000000000 --- 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 or the MIT license -// , 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 0000000000000..c912aa789bf6b --- /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 or the MIT license +; , 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 6a3e7b7513cbc..daa46bab404df 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