From a49b765f9a5b5926e338da30fcaae59ff1ae5c02 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Mon, 5 May 2014 10:07:49 +0300 Subject: [PATCH] Basic iOS support --- src/liblibc/lib.rs | 13 +++++ src/libnative/io/c_unix.rs | 7 +++ src/libnative/io/file_unix.rs | 3 +- src/libnative/io/mod.rs | 1 + src/libnative/io/net.rs | 3 +- src/libnative/io/process.rs | 1 + src/libnative/io/timer_unix.rs | 19 +++++- src/librustc/back/arm.rs | 8 +++ src/librustc/back/link.rs | 70 +++++++++++++++------- src/librustc/back/mips.rs | 8 +++ src/librustc/back/rpath.rs | 2 +- src/librustc/back/x86.rs | 8 +++ src/librustc/back/x86_64.rs | 6 ++ src/librustc/driver/config.rs | 7 ++- src/librustc/driver/session.rs | 1 - src/librustc/metadata/creader.rs | 3 +- src/librustc/metadata/loader.rs | 9 ++- src/librustc/middle/trans/cabi_x86.rs | 4 +- src/librustc/middle/trans/cleanup.rs | 2 +- src/librustc/middle/trans/debuginfo.rs | 3 +- src/librustdoc/flock.rs | 1 + src/librustrt/args.rs | 1 + src/librustrt/lib.rs | 2 +- src/librustrt/libunwind.rs | 25 +++++++- src/librustrt/local_ptr.rs | 5 +- src/librustrt/mutex.rs | 5 ++ src/librustrt/stack.rs | 12 ++-- src/librustrt/thread.rs | 2 - src/librustrt/thread_local_storage.rs | 3 +- src/librustrt/unwind.rs | 64 +++++++++++++++++++- src/libstd/dynamic_lib.rs | 3 +- src/libstd/os.rs | 81 ++++++++++++++++++++++++++ src/libstd/rand/os.rs | 69 +++++++++++++++++++++- src/libstd/rt/backtrace.rs | 60 ++++++++++++++++--- src/libstd/rtdeps.rs | 4 ++ src/libsyntax/abi.rs | 2 +- src/libtime/lib.rs | 9 ++- 37 files changed, 461 insertions(+), 65 deletions(-) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index ff87b7fb007..9ed0d50a03e 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -278,10 +278,13 @@ pub use consts::os::extra::{MAP_STACK}; pub use consts::os::bsd44::{TCP_KEEPIDLE}; #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] pub use consts::os::bsd44::{TCP_KEEPALIVE}; #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] pub use consts::os::extra::{F_FULLFSYNC}; #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] pub use types::os::arch::extra::{mach_timebase_info}; @@ -1286,6 +1289,7 @@ pub mod types { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] pub mod os { pub mod common { pub mod posix01 { @@ -3106,6 +3110,7 @@ pub mod consts { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] pub mod os { pub mod c95 { use types::os::arch::c95::{c_int, c_uint}; @@ -3769,6 +3774,7 @@ pub mod funcs { #[cfg(target_os = "linux")] #[cfg(target_os = "android")] #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] pub mod posix88 { pub mod stat_ { @@ -3783,6 +3789,7 @@ pub mod funcs { #[cfg(target_os = "linux")] #[cfg(target_os = "freebsd")] #[cfg(target_os = "android")] + #[cfg(target_os = "ios")] pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int; #[cfg(target_os = "macos")] @@ -3795,6 +3802,7 @@ pub mod funcs { #[cfg(target_os = "linux")] #[cfg(target_os = "freebsd")] #[cfg(target_os = "android")] + #[cfg(target_os = "ios")] pub fn stat(path: *c_char, buf: *mut stat) -> c_int; #[cfg(target_os = "macos")] @@ -3967,6 +3975,7 @@ pub mod funcs { #[cfg(target_os = "linux")] #[cfg(target_os = "android")] #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] pub mod posix01 { pub mod stat_ { @@ -3977,6 +3986,7 @@ pub mod funcs { #[cfg(target_os = "linux")] #[cfg(target_os = "freebsd")] #[cfg(target_os = "android")] + #[cfg(target_os = "ios")] pub fn lstat(path: *c_char, buf: *mut stat) -> c_int; #[cfg(target_os = "macos")] @@ -4076,6 +4086,7 @@ pub mod funcs { #[cfg(target_os = "linux")] #[cfg(target_os = "android")] #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] pub mod posix08 { pub mod unistd { @@ -4156,6 +4167,7 @@ pub mod funcs { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] pub mod bsd44 { use types::common::c95::{c_void}; @@ -4209,6 +4221,7 @@ pub mod funcs { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] pub mod extra { use types::os::arch::c95::{c_char, c_int}; diff --git a/src/libnative/io/c_unix.rs b/src/libnative/io/c_unix.rs index e6cb5cb76f1..70fd6310070 100644 --- a/src/libnative/io/c_unix.rs +++ b/src/libnative/io/c_unix.rs @@ -20,6 +20,7 @@ pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD}; use libc; #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] pub static FIONBIO: libc::c_ulong = 0x8004667e; #[cfg(target_os = "linux", not(target_arch = "mips"))] @@ -29,6 +30,7 @@ pub static FIONBIO: libc::c_ulong = 0x5421; pub static FIONBIO: libc::c_ulong = 0x667e; #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] pub static FIOCLEX: libc::c_ulong = 0x20006601; #[cfg(target_os = "linux", not(target_arch = "mips"))] @@ -38,6 +40,7 @@ pub static FIOCLEX: libc::c_ulong = 0x5451; pub static FIOCLEX: libc::c_ulong = 0x6601; #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] pub static MSG_DONTWAIT: libc::c_int = 0x80; #[cfg(target_os = "linux")] @@ -75,6 +78,7 @@ extern { } #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] mod select { pub static FD_SETSIZE: uint = 1024; @@ -187,6 +191,7 @@ mod signal { } #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] mod signal { use libc; @@ -201,6 +206,7 @@ mod signal { pub static SIGCHLD: libc::c_int = 20; #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] pub type sigset_t = u32; #[cfg(target_os = "freebsd")] pub struct sigset_t { @@ -219,6 +225,7 @@ mod signal { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] pub struct sigaction { pub sa_handler: extern fn(libc::c_int), sa_tramp: *mut libc::c_void, diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs index fda9b7b1932..f521934c0f9 100644 --- a/src/libnative/io/file_unix.rs +++ b/src/libnative/io/file_unix.rs @@ -133,6 +133,7 @@ impl rtio::RtioFileStream for FileDesc { return super::mkerr_libc(os_datasync(self.fd())); #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] fn os_datasync(fd: c_int) -> c_int { unsafe { libc::fcntl(fd, libc::F_FULLFSYNC) } } @@ -140,7 +141,7 @@ impl rtio::RtioFileStream for FileDesc { fn os_datasync(fd: c_int) -> c_int { retry(|| unsafe { libc::fdatasync(fd) }) } - #[cfg(not(target_os = "macos"), not(target_os = "linux"))] + #[cfg(not(target_os = "macos"), not(target_os = "ios"), not(target_os = "linux"))] fn os_datasync(fd: c_int) -> c_int { retry(|| unsafe { libc::fsync(fd) }) } diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 4158db7bb8e..6dc2482ab0c 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -50,6 +50,7 @@ pub mod file; pub mod file; #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] #[cfg(target_os = "android")] #[cfg(target_os = "linux")] diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index e7effbd6bdb..30ea80a1296 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -320,6 +320,7 @@ impl TcpStream { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> { setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, seconds as libc::c_int) @@ -329,7 +330,7 @@ impl TcpStream { setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, seconds as libc::c_int) } - #[cfg(not(target_os = "macos"), not(target_os = "freebsd"))] + #[cfg(not(target_os = "macos"), not(target_os = "ios"), not(target_os = "freebsd"))] fn set_tcp_keepalive(&mut self, _seconds: uint) -> IoResult<()> { Ok(()) } diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs index d8486cb9f09..f26d87ba1b5 100644 --- a/src/libnative/io/process.rs +++ b/src/libnative/io/process.rs @@ -769,6 +769,7 @@ fn translate_status(status: c_int) -> rtio::ProcessExit { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] mod imp { pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 } diff --git a/src/libnative/io/timer_unix.rs b/src/libnative/io/timer_unix.rs index 11f9c4b3d8c..ca0a810890c 100644 --- a/src/libnative/io/timer_unix.rs +++ b/src/libnative/io/timer_unix.rs @@ -93,7 +93,20 @@ pub fn now() -> u64 { } } -fn helper(input: libc::c_int, messages: Receiver, _: ()) { + +// Note: although the last parameter isn't used there is no way now to +// convert it to unit type, because LLVM dies in SjLj preparation +// step (unfortunately iOS uses SjLJ exceptions) +// +// It's definitely a temporary workaround just to get it working. +// So far it looks like an LLVM issue and it was reported: +// http://llvm.org/bugs/show_bug.cgi?id=19855 +// Actually this issue is pretty common while compiling for armv7 iOS +// and in most cases it is simply solved by using --opt-level=2 (or -O) +// +// For this specific case unfortunately turning optimizations wasn't +// enough. +fn helper(input: libc::c_int, messages: Receiver, _: int) { let mut set: c::fd_set = unsafe { mem::zeroed() }; let mut fd = FileDesc::new(input, true); @@ -202,7 +215,9 @@ fn helper(input: libc::c_int, messages: Receiver, _: ()) { impl Timer { pub fn new() -> IoResult { - unsafe { HELPER.boot(|| {}, helper); } + // See notes above regarding using int return value + // instead of () + unsafe { HELPER.boot(|| {0}, helper); } static mut ID: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; let id = unsafe { ID.fetch_add(1, atomics::Relaxed) }; diff --git a/src/librustc/back/arm.rs b/src/librustc/back/arm.rs index e5e8126ace1..7a944fd5abe 100644 --- a/src/librustc/back/arm.rs +++ b/src/librustc/back/arm.rs @@ -34,6 +34,14 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -a0:0:64-n32".to_string() } + abi::OsiOS => { + "e-p:32:32:32\ + -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ + -f32:32:32-f64:64:64\ + -v64:64:64-v128:64:128\ + -a0:0:64-n32".to_string() + } + abi::OsWin32 => { "e-p:32:32:32\ -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 55998f254ed..ab4eda33d75 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -114,6 +114,13 @@ pub mod write { // which are *far* more efficient. This is obviously undesirable in some // cases, so if any sort of target feature is specified we don't append v7 // to the feature list. + // + // On iOS only armv7 and newer are supported. So it is useful to + // get all hardware potential via VFP3 (hardware floating point) + // and NEON (SIMD) instructions supported by LLVM. + // Note that without those flags various linking errors might + // arise as some of intrinsicts are converted into function calls + // and nobody provides implementations those functions fn target_feature<'a>(sess: &'a Session) -> &'a str { match sess.targ_cfg.os { abi::OsAndroid => { @@ -122,7 +129,10 @@ pub mod write { } else { sess.opts.cg.target_feature.as_slice() } - } + }, + abi::OsiOS if sess.targ_cfg.arch == abi::Arm => { + "+v7,+thumb2,+vfp3,+neon" + }, _ => sess.opts.cg.target_feature.as_slice() } } @@ -827,15 +837,23 @@ pub fn filename_for_input(sess: &Session, crate_type: config::CrateType, out_filename.with_filename(format!("lib{}.rlib", libname)) } config::CrateTypeDylib => { - let (prefix, suffix) = match sess.targ_cfg.os { - abi::OsWin32 => (loader::WIN32_DLL_PREFIX, loader::WIN32_DLL_SUFFIX), - abi::OsMacos => (loader::MACOS_DLL_PREFIX, loader::MACOS_DLL_SUFFIX), - abi::OsLinux => (loader::LINUX_DLL_PREFIX, loader::LINUX_DLL_SUFFIX), - abi::OsAndroid => (loader::ANDROID_DLL_PREFIX, loader::ANDROID_DLL_SUFFIX), - abi::OsFreebsd => (loader::FREEBSD_DLL_PREFIX, loader::FREEBSD_DLL_SUFFIX), - }; - out_filename.with_filename(format!("{}{}{}", prefix, libname, - suffix)) + // There is no support of DyLibs on iOS + if sess.targ_cfg.os == abi::OsiOS { + out_filename.with_filename(format!("lib{}.a", libname)) + } else { + let (prefix, suffix) = match sess.targ_cfg.os { + abi::OsWin32 => (loader::WIN32_DLL_PREFIX, loader::WIN32_DLL_SUFFIX), + abi::OsMacos => (loader::MACOS_DLL_PREFIX, loader::MACOS_DLL_SUFFIX), + abi::OsLinux => (loader::LINUX_DLL_PREFIX, loader::LINUX_DLL_SUFFIX), + abi::OsAndroid => (loader::ANDROID_DLL_PREFIX, loader::ANDROID_DLL_SUFFIX), + abi::OsFreebsd => (loader::FREEBSD_DLL_PREFIX, loader::FREEBSD_DLL_SUFFIX), + abi::OsiOS => unreachable!(), + }; + out_filename.with_filename(format!("{}{}{}", + prefix, + libname, + suffix)) + } } config::CrateTypeStaticlib => { out_filename.with_filename(format!("lib{}.a", libname)) @@ -886,7 +904,14 @@ fn link_binary_output(sess: &Session, link_natively(sess, trans, false, &obj_filename, &out_filename); } config::CrateTypeDylib => { - link_natively(sess, trans, true, &obj_filename, &out_filename); + if sess.targ_cfg.os == abi::OsiOS { + sess.warn(format!("No dylib for iOS -> saving static library {} to {}", + obj_filename.display(), out_filename.display()).as_slice()); + link_staticlib(sess, &obj_filename, &out_filename); + } + else { + link_natively(sess, trans, true, &obj_filename, &out_filename); + } } } @@ -991,7 +1016,7 @@ fn link_rlib<'a>(sess: &'a Session, // symbol table of the archive. This currently dies on OSX (see // #11162), and isn't necessary there anyway match sess.targ_cfg.os { - abi::OsMacos => {} + abi::OsMacos | abi::OsiOS => {} _ => { a.update_symbols(); } } } @@ -1104,15 +1129,16 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool, // On OSX, debuggers need this utility to get run to do some munging of // the symbols - if sess.targ_cfg.os == abi::OsMacos && (sess.opts.debuginfo != NoDebugInfo) { - match Command::new("dsymutil").arg(out_filename).status() { - Ok(..) => {} - Err(e) => { - sess.err(format!("failed to run dsymutil: {}", e).as_slice()); - sess.abort_if_errors(); + if (sess.targ_cfg.os == abi::OsMacos || sess.targ_cfg.os == abi::OsiOS) + && (sess.opts.debuginfo != NoDebugInfo) { + match Command::new("dsymutil").arg(out_filename).status() { + Ok(..) => {} + Err(e) => { + sess.err(format!("failed to run dsymutil: {}", e).as_slice()); + sess.abort_if_errors(); + } } } - } } fn link_args(cmd: &mut Command, @@ -1169,7 +1195,7 @@ fn link_args(cmd: &mut Command, // already done the best it can do, and we also don't want to eliminate the // metadata. If we're building an executable, however, --gc-sections drops // the size of hello world from 1.8MB to 597K, a 67% reduction. - if !dylib && sess.targ_cfg.os != abi::OsMacos { + if !dylib && sess.targ_cfg.os != abi::OsMacos && sess.targ_cfg.os != abi::OsiOS { cmd.arg("-Wl,--gc-sections"); } @@ -1185,7 +1211,7 @@ fn link_args(cmd: &mut Command, sess.opts.optimize == config::Aggressive { cmd.arg("-Wl,-O1"); } - } else if sess.targ_cfg.os == abi::OsMacos { + } else if sess.targ_cfg.os == abi::OsMacos || sess.targ_cfg.os == abi::OsiOS { // The dead_strip option to the linker specifies that functions and data // unreachable by the entry point will be removed. This is quite useful // with Rust's compilation model of compiling libraries at a time into @@ -1348,7 +1374,7 @@ fn add_local_native_libraries(cmd: &mut Command, sess: &Session) { // For those that support this, we ensure we pass the option if the library // was flagged "static" (most defaults are dynamic) to ensure that if // libfoo.a and libfoo.so both exist that the right one is chosen. - let takes_hints = sess.targ_cfg.os != abi::OsMacos; + let takes_hints = sess.targ_cfg.os != abi::OsMacos && sess.targ_cfg.os != abi::OsiOS; for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() { match kind { diff --git a/src/librustc/back/mips.rs b/src/librustc/back/mips.rs index 9f640a2c9cb..ea9879dbf49 100644 --- a/src/librustc/back/mips.rs +++ b/src/librustc/back/mips.rs @@ -29,6 +29,14 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -a0:0:64-n32".to_string() } + abi::OsiOS => { + "E-p:32:32:32\ + -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ + -f32:32:32-f64:64:64\ + -v64:64:64-v128:64:128\ + -a0:0:64-n32".to_string() + } + abi::OsWin32 => { "E-p:32:32:32\ -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index cdf49304f9a..a458cf22a5b 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -122,7 +122,7 @@ pub fn get_rpath_relative_to_output(os: abi::Os, abi::OsAndroid | abi::OsLinux | abi::OsFreebsd => "$ORIGIN", abi::OsMacos => "@loader_path", - abi::OsWin32 => unreachable!() + abi::OsWin32 | abi::OsiOS => unreachable!() }; let mut lib = fs::realpath(&os::make_absolute(lib)).unwrap(); diff --git a/src/librustc/back/x86.rs b/src/librustc/back/x86.rs index 3ef013d47c9..90106e9e030 100644 --- a/src/librustc/back/x86.rs +++ b/src/librustc/back/x86.rs @@ -31,6 +31,14 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -n8:16:32".to_string() } + abi::OsiOS => { + "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\ + -i32:32:32-i64:32:64\ + -f32:32:32-f64:32:64-v64:64:64\ + -v128:128:128-a0:0:64-f80:128:128\ + -n8:16:32".to_string() + } + abi::OsWin32 => { "e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32".to_string() } diff --git a/src/librustc/back/x86_64.rs b/src/librustc/back/x86_64.rs index 80dd2b2c516..55b0eca7be7 100644 --- a/src/librustc/back/x86_64.rs +++ b/src/librustc/back/x86_64.rs @@ -28,6 +28,12 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs s0:64:64-f80:128:128-n8:16:32:64".to_string() } + abi::OsiOS => { + "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + s0:64:64-f80:128:128-n8:16:32:64".to_string() + } + abi::OsWin32 => { // FIXME: Test this. Copied from linux (#2398) "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index 186db839e33..2f7dc136ef2 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -362,7 +362,8 @@ pub fn cfg_os_to_meta_os(os: abi::Os) -> metadata::loader::Os { abi::OsLinux => loader::OsLinux, abi::OsAndroid => loader::OsAndroid, abi::OsMacos => loader::OsMacos, - abi::OsFreebsd => loader::OsFreebsd + abi::OsFreebsd => loader::OsFreebsd, + abi::OsiOS => loader::OsiOS, } } @@ -373,6 +374,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { abi::OsLinux => InternedString::new("linux"), abi::OsAndroid => InternedString::new("android"), abi::OsFreebsd => InternedString::new("freebsd"), + abi::OsiOS => InternedString::new("ios"), }; // ARM is bi-endian, however using NDK seems to default @@ -438,7 +440,8 @@ static os_names : &'static [(&'static str, abi::Os)] = &'static [ ("darwin", abi::OsMacos), ("android", abi::OsAndroid), ("linux", abi::OsLinux), - ("freebsd", abi::OsFreebsd)]; + ("freebsd", abi::OsFreebsd), + ("ios", abi::OsiOS)]; pub fn get_arch(triple: &str) -> Option { for &(arch, abi) in architecture_abis.iter() { diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 773b9e6e0aa..bc22b3ca7e2 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -249,4 +249,3 @@ pub fn expect(sess: &Session, opt: Option, msg: || -> String) -> T { diagnostic::expect(sess.diagnostic(), opt, msg) } - diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 4df21fbc974..63b177b0eb7 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -215,7 +215,8 @@ fn visit_item(e: &Env, i: &ast::Item) { Some(k) => { if k.equiv(&("static")) { cstore::NativeStatic - } else if e.sess.targ_cfg.os == abi::OsMacos && + } else if (e.sess.targ_cfg.os == abi::OsMacos || + e.sess.targ_cfg.os == abi::OsiOS) && k.equiv(&("framework")) { cstore::NativeFramework } else if k.equiv(&("framework")) { diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index cfda97ad26f..a674b6cf5a9 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -39,6 +39,9 @@ use time; pub static MACOS_DLL_PREFIX: &'static str = "lib"; pub static MACOS_DLL_SUFFIX: &'static str = ".dylib"; +pub static IOS_DLL_PREFIX: &'static str = "lib"; +pub static IOS_DLL_SUFFIX: &'static str = ".dylib"; + pub static WIN32_DLL_PREFIX: &'static str = ""; pub static WIN32_DLL_SUFFIX: &'static str = ".dll"; @@ -56,7 +59,8 @@ pub enum Os { OsWin32, OsLinux, OsAndroid, - OsFreebsd + OsFreebsd, + OsiOS } pub struct CrateMismatch { @@ -455,6 +459,7 @@ impl<'a> Context<'a> { OsLinux => (LINUX_DLL_PREFIX, LINUX_DLL_SUFFIX), OsAndroid => (ANDROID_DLL_PREFIX, ANDROID_DLL_SUFFIX), OsFreebsd => (FREEBSD_DLL_PREFIX, FREEBSD_DLL_SUFFIX), + OsiOS => (IOS_DLL_PREFIX, IOS_DLL_SUFFIX), } } @@ -593,6 +598,7 @@ fn get_metadata_section_imp(os: Os, filename: &Path) -> Result &'static str { match os { OsMacos => "__DATA,__note.rustc", + OsiOS => "__DATA,__note.rustc", OsWin32 => ".note.rustc", OsLinux => ".note.rustc", OsAndroid => ".note.rustc", @@ -603,6 +609,7 @@ pub fn meta_section_name(os: Os) -> &'static str { pub fn read_meta_section_name(os: Os) -> &'static str { match os { OsMacos => "__note.rustc", + OsiOS => "__note.rustc", OsWin32 => ".note.rustc", OsLinux => ".note.rustc", OsAndroid => ".note.rustc", diff --git a/src/librustc/middle/trans/cabi_x86.rs b/src/librustc/middle/trans/cabi_x86.rs index 93b6fdd8988..d10f6b72820 100644 --- a/src/librustc/middle/trans/cabi_x86.rs +++ b/src/librustc/middle/trans/cabi_x86.rs @@ -9,7 +9,7 @@ // except according to those terms. -use syntax::abi::{OsWin32, OsMacos}; +use syntax::abi::{OsWin32, OsMacos, OsiOS}; use lib::llvm::*; use super::cabi::*; use super::common::*; @@ -36,7 +36,7 @@ pub fn compute_abi_info(ccx: &CrateContext, enum Strategy { RetValue(Type), RetPointer } let strategy = match ccx.sess().targ_cfg.os { - OsWin32 | OsMacos => { + OsWin32 | OsMacos | OsiOS => { match llsize_of_alloc(ccx, rty) { 1 => RetValue(Type::i8(ccx)), 2 => RetValue(Type::i16(ccx)), diff --git a/src/librustc/middle/trans/cleanup.rs b/src/librustc/middle/trans/cleanup.rs index b28db3d378b..24f30bae75a 100644 --- a/src/librustc/middle/trans/cleanup.rs +++ b/src/librustc/middle/trans/cleanup.rs @@ -680,7 +680,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> { Some(llpersonality) => llpersonality, None => { let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); - let f = base::decl_cdecl_fn(self.ccx.llmod, + let f = base::decl_cdecl_fn(self.ccx, "rust_eh_personality", fty, ty::mk_i32()); diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index db17000abb3..c50badac531 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -277,7 +277,8 @@ pub fn finalize(cx: &CrateContext) { // instruct LLVM to emit an older version of dwarf, however, // for OS X to understand. For more info see #11352 // This can be overridden using --llvm-opts -dwarf-version,N. - if cx.sess().targ_cfg.os == abi::OsMacos { + if cx.sess().targ_cfg.os == abi::OsMacos || + cx.sess().targ_cfg.os == abi::OsiOS { "Dwarf Version".with_c_str( |s| llvm::LLVMRustAddModuleFlag(cx.llmod, s, 2)); } else { diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs index 8ad10a686e6..800e7f065f1 100644 --- a/src/librustdoc/flock.rs +++ b/src/librustdoc/flock.rs @@ -64,6 +64,7 @@ mod imp { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] mod os { use libc; diff --git a/src/librustrt/args.rs b/src/librustrt/args.rs index 0789bf7f906..d6d4b18051b 100644 --- a/src/librustrt/args.rs +++ b/src/librustrt/args.rs @@ -145,6 +145,7 @@ mod imp { } #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] #[cfg(target_os = "win32")] mod imp { use core::prelude::*; diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs index 76cbeef443e..e17a43322ba 100644 --- a/src/librustrt/lib.rs +++ b/src/librustrt/lib.rs @@ -164,7 +164,7 @@ pub unsafe fn cleanup() { pub mod shouldnt_be_public { #[cfg(not(test))] pub use super::local_ptr::native::maybe_tls_key; - #[cfg(not(windows), not(target_os = "android"))] + #[cfg(not(windows), not(target_os = "android"), not(target_os = "ios"))] pub use super::local_ptr::compiled::RT_TLS_PTR; } diff --git a/src/librustrt/libunwind.rs b/src/librustrt/libunwind.rs index 846ec248805..50c2aba2b5c 100644 --- a/src/librustrt/libunwind.rs +++ b/src/librustrt/libunwind.rs @@ -17,6 +17,7 @@ use libc; #[cfg(not(target_arch = "arm"))] +#[cfg(target_os = "ios")] #[repr(C)] pub enum _Unwind_Action { _UA_SEARCH_PHASE = 1, @@ -61,9 +62,12 @@ pub static unwinder_private_data_size: int = 5; #[cfg(target_arch = "x86_64")] pub static unwinder_private_data_size: int = 2; -#[cfg(target_arch = "arm")] +#[cfg(target_arch = "arm", not(target_os = "ios"))] pub static unwinder_private_data_size: int = 20; +#[cfg(target_arch = "arm", target_os = "ios")] +pub static unwinder_private_data_size: int = 5; + #[cfg(target_arch = "mips")] pub static unwinder_private_data_size: int = 2; @@ -89,8 +93,27 @@ extern {} #[link(name = "gcc")] extern {} + extern "C" { + // iOS on armv7 uses SjLj exceptions and requires to link + // agains corresponding routine (..._SjLj_...) + // So here we just skip linking for iOS + #[cfg(not(target_os = "ios", target_arch = "arm"))] pub fn _Unwind_RaiseException(exception: *_Unwind_Exception) -> _Unwind_Reason_Code; pub fn _Unwind_DeleteException(exception: *_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(target_os = "ios", target_arch = "arm")] +#[inline(always)] +pub unsafe fn _Unwind_RaiseException(exc: *_Unwind_Exception) + -> _Unwind_Reason_Code { + extern "C" { + fn _Unwind_SjLj_RaiseException(e: *_Unwind_Exception) + -> _Unwind_Reason_Code; } + + _Unwind_SjLj_RaiseException(exc) +} diff --git a/src/librustrt/local_ptr.rs b/src/librustrt/local_ptr.rs index 91e3409892e..b6858be32b7 100644 --- a/src/librustrt/local_ptr.rs +++ b/src/librustrt/local_ptr.rs @@ -24,10 +24,11 @@ use alloc::owned::Box; #[cfg(windows)] // mingw-w32 doesn't like thread_local things #[cfg(target_os = "android")] // see #10686 +#[cfg(target_os = "ios")] pub use self::native::{init, cleanup, put, take, try_take, unsafe_take, exists, unsafe_borrow, try_unsafe_borrow}; -#[cfg(not(windows), not(target_os = "android"))] +#[cfg(not(windows), not(target_os = "android"), not(target_os = "ios"))] pub use self::compiled::{init, cleanup, put, take, try_take, unsafe_take, exists, unsafe_borrow, try_unsafe_borrow}; @@ -81,7 +82,7 @@ pub unsafe fn borrow() -> Borrowed { /// implemented using LLVM's thread_local attribute which isn't necessarily /// working on all platforms. This implementation is faster, however, so we use /// it wherever possible. -#[cfg(not(windows), not(target_os = "android"))] +#[cfg(not(windows), not(target_os = "android"), not(target_os = "ios"))] pub mod compiled { use core::prelude::*; diff --git a/src/librustrt/mutex.rs b/src/librustrt/mutex.rs index eec19e9d5db..26359ff7f6e 100644 --- a/src/librustrt/mutex.rs +++ b/src/librustrt/mutex.rs @@ -283,6 +283,7 @@ mod imp { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] mod os { use libc; @@ -294,6 +295,10 @@ mod imp { static __PTHREAD_MUTEX_SIZE__: uint = 40; #[cfg(target_arch = "x86")] static __PTHREAD_COND_SIZE__: uint = 24; + #[cfg(target_arch = "arm")] + static __PTHREAD_MUTEX_SIZE__: uint = 40; + #[cfg(target_arch = "arm")] + static __PTHREAD_COND_SIZE__: uint = 24; static _PTHREAD_MUTEX_SIG_init: libc::c_long = 0x32AAABA7; static _PTHREAD_COND_SIG_init: libc::c_long = 0x3CB0B1BB; diff --git a/src/librustrt/stack.rs b/src/librustrt/stack.rs index aac773f6f85..e6fa845bedc 100644 --- a/src/librustrt/stack.rs +++ b/src/librustrt/stack.rs @@ -173,7 +173,8 @@ pub unsafe fn record_sp_limit(limit: uint) { return target_record_sp_limit(limit); // x86-64 - #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)] + #[cfg(target_arch = "x86_64", target_os = "macos")] + #[cfg(target_arch = "x86_64", target_os = "ios")] #[inline(always)] unsafe fn target_record_sp_limit(limit: uint) { asm!("movq $$0x60+90*8, %rsi movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile") @@ -195,7 +196,8 @@ pub unsafe fn record_sp_limit(limit: uint) { } // x86 - #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)] + #[cfg(target_arch = "x86", target_os = "macos")] + #[cfg(target_arch = "x86", target_os = "ios")] #[inline(always)] unsafe fn target_record_sp_limit(limit: uint) { asm!("movl $$0x48+90*4, %eax movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile") @@ -243,7 +245,8 @@ pub unsafe fn get_sp_limit() -> uint { return target_get_sp_limit(); // x86-64 - #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)] + #[cfg(target_arch = "x86_64", target_os = "macos")] + #[cfg(target_arch = "x86_64", target_os = "ios")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { let limit; asm!("movq $$0x60+90*8, %rsi @@ -270,7 +273,8 @@ pub unsafe fn get_sp_limit() -> uint { } // x86 - #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)] + #[cfg(target_arch = "x86", target_os = "macos")] + #[cfg(target_arch = "x86", target_os = "ios")] #[inline(always)] unsafe fn target_get_sp_limit() -> uint { let limit; asm!("movl $$0x48+90*4, %eax diff --git a/src/librustrt/thread.rs b/src/librustrt/thread.rs index 4ef2cec19db..3dcd1c4a6f0 100644 --- a/src/librustrt/thread.rs +++ b/src/librustrt/thread.rs @@ -276,7 +276,6 @@ mod imp { } pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); } - // glibc >= 2.15 has a __pthread_get_minstack() function that returns // PTHREAD_STACK_MIN plus however many bytes are needed for thread-local // storage. We need that information to avoid blowing up when a small stack @@ -345,4 +344,3 @@ mod tests { assert_eq!(42, Thread::start_stack(1, proc () 42).join()); } } - diff --git a/src/librustrt/thread_local_storage.rs b/src/librustrt/thread_local_storage.rs index 2cdeb21fb83..4a7be39e6b8 100644 --- a/src/librustrt/thread_local_storage.rs +++ b/src/librustrt/thread_local_storage.rs @@ -37,13 +37,14 @@ pub unsafe fn destroy(key: Key) { assert!(pthread_key_delete(key) == 0); } -#[cfg(target_os="macos")] +#[cfg(target_os = "macos")] #[allow(non_camel_case_types)] // foreign type type pthread_key_t = ::libc::c_ulong; #[cfg(target_os="linux")] #[cfg(target_os="freebsd")] #[cfg(target_os="android")] +#[cfg(target_os = "ios")] #[allow(non_camel_case_types)] // foreign type type pthread_key_t = ::libc::c_uint; diff --git a/src/librustrt/unwind.rs b/src/librustrt/unwind.rs index f7475db1552..e60c50f0adb 100644 --- a/src/librustrt/unwind.rs +++ b/src/librustrt/unwind.rs @@ -285,16 +285,74 @@ pub mod eabi { } else { // cleanup phase unsafe { - __gcc_personality_v0(version, actions, exception_class, ue_header, + __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(target_os = "ios", target_arch = "arm", not(test))] +#[doc(hidden)] +#[allow(visible_private_types)] +pub mod eabi { + use uw = libunwind; + use libc::c_int; + + extern "C" { + #[cfg(target_os = "ios", target_arch = "arm")] + fn __gcc_personality_sj0(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + ue_header: *uw::_Unwind_Exception, + context: *uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code; + } + + #[lang="eh_personality"] + #[no_mangle] // so we can reference it by name from middle/trans/base.rs + pub extern "C" fn rust_eh_personality( + version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + ue_header: *uw::_Unwind_Exception, + context: *uw::_Unwind_Context + ) -> uw::_Unwind_Reason_Code + { + unsafe { + __gcc_personality_sj0(version, actions, exception_class, ue_header, + context) + } + } + + #[no_mangle] // referenced from rust_try.ll + pub extern "C" fn rust_eh_personality_catch( + version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + ue_header: *uw::_Unwind_Exception, + context: *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(target_arch = "arm", not(test))] +#[cfg(target_arch = "arm", not(test), not(target_os = "ios"))] #[allow(visible_private_types)] pub mod eabi { use uw = libunwind; @@ -332,7 +390,7 @@ pub mod eabi { } else { // cleanup phase unsafe { - __gcc_personality_v0(state, ue_header, context) + __gcc_personality_v0(state, ue_header, context) } } } diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index fa6efc8a4b1..5dbed6844c3 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -153,7 +153,7 @@ impl DynamicLibrary { } } -#[cfg(test)] +#[cfg(test, not(target_os = "ios"))] mod test { use super::*; use prelude::*; @@ -205,6 +205,7 @@ mod test { #[cfg(target_os = "linux")] #[cfg(target_os = "android")] #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] pub mod dl { use prelude::*; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index cc76cde7baf..f6b1c04dd34 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -552,6 +552,7 @@ pub fn pipe() -> Pipe { /// Returns the proper dll filename for the given basename of a file /// as a String. +#[cfg(not(target_os="ios"))] pub fn dll_filename(base: &str) -> String { format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX) } @@ -608,6 +609,7 @@ pub fn self_exe_name() -> Option { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] fn load_self() -> Option> { unsafe { use libc::funcs::extra::_NSGetExecutablePath; @@ -802,6 +804,7 @@ pub fn change_dir(p: &Path) -> bool { /// Returns the platform-specific value of errno pub fn errno() -> int { #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] #[cfg(target_os = "freebsd")] fn errno_location() -> *c_int { extern { @@ -850,6 +853,7 @@ pub fn error_string(errnum: uint) -> String { #[cfg(unix)] fn strerror(errnum: uint) -> String { #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] #[cfg(target_os = "android")] #[cfg(target_os = "freebsd")] fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) @@ -995,6 +999,64 @@ fn real_args_as_bytes() -> Vec> { } } +// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs +// and use underscores in their names - they're most probably +// are considered private and therefore should be avoided +// Here is another way to get arguments using Objective C +// runtime +// +// In general it looks like: +// res = Vec::new() +// let args = [[NSProcessInfo processInfo] arguments] +// for i in range(0, [args count]) +// res.push([args objectAtIndex:i]) +// res +#[cfg(target_os = "ios")] +fn real_args_as_bytes() -> Vec> { + use c_str::CString; + use iter::range; + use mem; + + #[link(name = "objc")] + extern { + fn sel_registerName(name: *libc::c_uchar) -> Sel; + fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; + fn objc_getClass(class_name: *libc::c_uchar) -> NsId; + } + + #[link(name = "Foundation", kind = "framework")] + extern {} + + type Sel = *libc::c_void; + type NsId = *libc::c_void; + + let mut res = Vec::new(); + + unsafe { + let processInfoSel = sel_registerName("processInfo\0".as_ptr()); + let argumentsSel = sel_registerName("arguments\0".as_ptr()); + let utf8Sel = sel_registerName("UTF8String\0".as_ptr()); + let countSel = sel_registerName("count\0".as_ptr()); + let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr()); + + let klass = objc_getClass("NSProcessInfo\0".as_ptr()); + let info = objc_msgSend(klass, processInfoSel); + let args = objc_msgSend(info, argumentsSel); + + let cnt: int = mem::transmute(objc_msgSend(args, countSel)); + for i in range(0, cnt) { + let tmp = objc_msgSend(args, objectAtSel, i); + let utf_c_str: *libc::c_char = mem::transmute(objc_msgSend(tmp, utf8Sel)); + let s = CString::new(utf_c_str, false); + if s.is_not_null() { + res.push(Vec::from_slice(s.as_bytes_no_nul())) + } + } + } + + res +} + #[cfg(target_os = "linux")] #[cfg(target_os = "android")] #[cfg(target_os = "freebsd")] @@ -1532,6 +1594,25 @@ pub mod consts { pub static EXE_EXTENSION: &'static str = ""; } +#[cfg(target_os = "ios")] +pub mod consts { + pub use os::arch_consts::ARCH; + + pub static FAMILY: &'static str = "unix"; + + /// A string describing the specific operating system in use: in this + /// case, `ios`. + pub static SYSNAME: &'static str = "ios"; + + /// Specifies the filename suffix used for executable binaries on this + /// platform: in this case, the empty string. + pub static EXE_SUFFIX: &'static str = ""; + + /// Specifies the file extension, if any, used for executable binaries + /// on this platform: in this case, the empty string. + pub static EXE_EXTENSION: &'static str = ""; +} + #[cfg(target_os = "freebsd")] pub mod consts { pub use os::arch_consts::ARCH; diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 2654b7a1acc..f507011c2b9 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -13,7 +13,7 @@ pub use self::imp::OsRng; -#[cfg(unix)] +#[cfg(unix, not(target_os = "ios"))] mod imp { use io::{IoResult, File}; use path::Path; @@ -28,7 +28,7 @@ mod imp { /// `/dev/urandom`. /// - Windows: calls `CryptGenRandom`, using the default cryptographic /// service provider with the `PROV_RSA_FULL` type. - /// + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed /// This does not block. #[cfg(unix)] pub struct OsRng { @@ -58,6 +58,71 @@ mod imp { } } +#[cfg(target_os = "ios")] +mod imp { + extern crate libc; + + use collections::Collection; + use io::{IoResult}; + use kinds::marker; + use mem; + use os; + use rand::Rng; + use result::{Ok}; + use self::libc::{c_int, size_t}; + use slice::MutableVector; + + /// A random number generator that retrieves randomness straight from + /// the operating system. Platform sources: + /// + /// - Unix-like systems (Linux, Android, Mac OSX): read directly from + /// `/dev/urandom`. + /// - Windows: calls `CryptGenRandom`, using the default cryptographic + /// service provider with the `PROV_RSA_FULL` type. + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// This does not block. + pub struct OsRng { + marker: marker::NoCopy + } + + struct SecRandom; + + static kSecRandomDefault: *SecRandom = 0 as *SecRandom; + + #[link(name = "Security", kind = "framework")] + extern "C" { + fn SecRandomCopyBytes(rnd: *SecRandom, count: size_t, bytes: *mut u8) -> c_int; + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> IoResult { + Ok(OsRng {marker: marker::NoCopy} ) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + let mut v = [0u8, .. 4]; + self.fill_bytes(v); + unsafe { mem::transmute(v) } + } + fn next_u64(&mut self) -> u64 { + let mut v = [0u8, .. 8]; + self.fill_bytes(v); + unsafe { mem::transmute(v) } + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let ret = unsafe { + SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr()) + }; + if ret == -1 { + fail!("couldn't generate random bytes: {}", os::last_os_error()); + } + } + } +} + #[cfg(windows)] mod imp { extern crate libc; diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index a1372b51d47..16b598b3ae7 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -237,22 +237,58 @@ fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> { #[cfg(unix)] mod imp { use c_str::CString; - use io::{IoResult, IoError, Writer}; + use io::{IoResult, Writer}; use libc; use mem; use option::{Some, None, Option}; use result::{Ok, Err}; use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; - struct Context<'a> { - idx: int, - writer: &'a mut Writer, - last_error: Option, + /// As always - iOS on arm uses SjLj exceptions and + /// _Unwind_Backtrace is even not available there. Still, + /// backtraces could be extracted using a backtrace function, + /// which thanks god is public + #[cfg(target_os = "ios", target_arch = "arm")] + #[inline(never)] + pub fn write(w: &mut Writer) -> IoResult<()> { + use iter::{Iterator, range}; + use result; + use slice::{MutableVector}; + + extern { + fn backtrace(buf: *mut *libc::c_void, sz: libc::c_int) -> libc::c_int; + } + + // while it doesn't requires lock for work as everything is + // local, it still displays much nicier backtraces when a + // couple of tasks fail simultaneously + static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; + let _g = unsafe { LOCK.lock() }; + + try!(writeln!(w, "stack backtrace:")); + // 100 lines should be enough + static size: libc::c_int = 100; + let mut buf: [*libc::c_void, ..size] = unsafe {mem::zeroed()}; + let cnt = unsafe { backtrace(buf.as_mut_ptr(), size) as uint}; + + // skipping the first one as it is write itself + result::fold_(range(1, cnt).map(|i| { + print(w, i as int, buf[i]) + })) } + #[cfg(not(target_os = "ios", target_arch = "arm"))] #[inline(never)] // if we know this is a function call, we can skip it when // tracing pub fn write(w: &mut Writer) -> IoResult<()> { + use io::IoError; + + struct Context<'a> { + idx: int, + writer: &'a mut Writer, + last_error: Option, + } + // When using libbacktrace, we use some necessary global state, so we // need to prevent more than one thread from entering this block. This // is semi-reasonable in terms of printing anyway, and we know that all @@ -291,7 +327,7 @@ mod imp { // instructions after it. This means that the return instruction // pointer points *outside* of the calling function, and by // unwinding it we go back to the original function. - let ip = if cfg!(target_os = "macos") { + let ip = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { ip } else { unsafe { uw::_Unwind_FindEnclosingFunction(ip) } @@ -323,6 +359,7 @@ mod imp { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] fn print(w: &mut Writer, idx: int, addr: *libc::c_void) -> IoResult<()> { use intrinsics; #[repr(C)] @@ -347,7 +384,7 @@ mod imp { } } - #[cfg(not(target_os = "macos"))] + #[cfg(not(target_os = "macos"), not(target_os = "ios"))] fn print(w: &mut Writer, idx: int, addr: *libc::c_void) -> IoResult<()> { use collections::Collection; use iter::Iterator; @@ -487,9 +524,14 @@ mod imp { /// Unwind library interface used for backtraces /// - /// Note that the native libraries come from librustrt, not this module. + /// Note that the native libraries come from librustrt, not this + /// module. + /// Note that dead code is allowed as here are just bindings + /// iOS doesn't use all of them it but adding more + /// platform-specific configs pollutes the code too much #[allow(non_camel_case_types)] #[allow(non_snake_case_functions)] + #[allow(dead_code)] mod uw { use libc; @@ -514,6 +556,8 @@ mod imp { arg: *libc::c_void) -> _Unwind_Reason_Code; extern { + // No native _Unwind_Backtrace on iOS + #[cfg(not(target_os = "ios", target_arch = "arm"))] pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, trace_argument: *libc::c_void) -> _Unwind_Reason_Code; diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index c804918ae4b..f8bfde52261 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -39,3 +39,7 @@ extern {} #[cfg(target_os = "macos")] #[link(name = "System")] extern {} + +#[cfg(target_os = "ios")] +#[link(name = "System")] +extern {} diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index cfe85995df6..ec54a033e71 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -11,7 +11,7 @@ use std::fmt; #[deriving(PartialEq)] -pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, } +pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, OsiOS, } #[deriving(PartialEq, Eq, Hash, Encodable, Decodable, Clone)] pub enum Abi { diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index 63523cd3a6f..b4a2e92cc12 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -48,7 +48,7 @@ mod rustrt { } } -#[cfg(unix, not(target_os = "macos"))] +#[cfg(unix, not(target_os = "macos"), not(target_os = "ios"))] mod imp { use libc::{c_int, timespec}; @@ -63,6 +63,7 @@ mod imp { } #[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] mod imp { use libc::{timeval, timezone, c_int, mach_timebase_info}; @@ -123,6 +124,7 @@ pub fn get_time() -> Timespec { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] unsafe fn os_get_time() -> (i64, i32) { use std::ptr; let mut tv = libc::timeval { tv_sec: 0, tv_usec: 0 }; @@ -130,7 +132,7 @@ pub fn get_time() -> Timespec { (tv.tv_sec as i64, tv.tv_usec * 1000) } - #[cfg(not(target_os = "macos"), not(windows))] + #[cfg(not(target_os = "macos"), not(target_os = "ios"), not(windows))] unsafe fn os_get_time() -> (i64, i32) { let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 }; imp::clock_gettime(libc::CLOCK_REALTIME, &mut tv); @@ -162,6 +164,7 @@ pub fn precise_time_ns() -> u64 { } #[cfg(target_os = "macos")] + #[cfg(target_os = "ios")] fn os_precise_time_ns() -> u64 { static mut TIMEBASE: libc::mach_timebase_info = libc::mach_timebase_info { numer: 0, denom: 0 }; @@ -175,7 +178,7 @@ pub fn precise_time_ns() -> u64 { } } - #[cfg(not(windows), not(target_os = "macos"))] + #[cfg(not(windows), not(target_os = "macos"), not(target_os = "ios"))] fn os_precise_time_ns() -> u64 { let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 }; unsafe {