]> git.lizzy.rs Git - rust.git/commitdiff
Add externfn macro and correctly label fixed_stack_segments
authorNiko Matsakis <niko@alum.mit.edu>
Thu, 15 Aug 2013 01:41:40 +0000 (21:41 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 19 Aug 2013 11:13:15 +0000 (07:13 -0400)
82 files changed:
doc/tutorial-ffi.md
src/libextra/c_vec.rs
src/libextra/flate.rs
src/libextra/rl.rs
src/libextra/test.rs
src/libextra/time.rs
src/librust/rust.rs
src/librustc/driver/driver.rs
src/librustc/lib/llvm.rs
src/librustc/middle/stack_check.rs
src/librustc/middle/trans/base.rs
src/librustc/rustc.rs
src/librusti/rusti.rs
src/librustpkg/util.rs
src/libstd/c_str.rs
src/libstd/io.rs
src/libstd/libc.rs
src/libstd/num/f32.rs
src/libstd/num/f64.rs
src/libstd/os.rs
src/libstd/path.rs
src/libstd/rand.rs
src/libstd/rt/args.rs
src/libstd/rt/borrowck.rs
src/libstd/rt/global_heap.rs
src/libstd/rt/local_heap.rs
src/libstd/rt/local_ptr.rs
src/libstd/rt/logging.rs
src/libstd/rt/mod.rs
src/libstd/rt/stack.rs
src/libstd/rt/task.rs
src/libstd/rt/test.rs
src/libstd/rt/thread.rs
src/libstd/rt/thread_local_storage.rs
src/libstd/rt/util.rs
src/libstd/rt/uv/mod.rs
src/libstd/rt/uv/uvio.rs
src/libstd/rt/uv/uvll.rs
src/libstd/run.rs
src/libstd/std.rs
src/libstd/str.rs
src/libstd/task/local_data_priv.rs
src/libstd/task/mod.rs
src/libstd/unstable/dynamic_lib.rs
src/libstd/unstable/mod.rs
src/libstd/unstable/sync.rs
src/libsyntax/ext/expand.rs
src/test/auxiliary/extern-crosscrate-source.rs
src/test/compile-fail/lint-unused-unsafe.rs
src/test/run-pass/anon-extern-mod-cross-crate-2.rs
src/test/run-pass/anon-extern-mod.rs
src/test/run-pass/c-stack-returning-int64.rs
src/test/run-pass/extern-call-deep.rs
src/test/run-pass/extern-call-deep2.rs
src/test/run-pass/extern-call-scrub.rs
src/test/run-pass/extern-call.rs
src/test/run-pass/extern-crosscrate.rs
src/test/run-pass/extern-pass-TwoU32s.rs
src/test/run-pass/extern-pass-TwoU64s-ref.rs
src/test/run-pass/extern-pass-TwoU64s.rs
src/test/run-pass/extern-pass-char.rs
src/test/run-pass/extern-pass-double.rs
src/test/run-pass/extern-pass-u32.rs
src/test/run-pass/extern-pass-u64.rs
src/test/run-pass/extern-return-TwoU16s.rs
src/test/run-pass/extern-return-TwoU32s.rs
src/test/run-pass/extern-return-TwoU64s.rs
src/test/run-pass/extern-return-TwoU8s.rs
src/test/run-pass/extern-stress.rs
src/test/run-pass/extern-yield.rs
src/test/run-pass/foreign-call-no-runtime.rs
src/test/run-pass/foreign-dupe.rs
src/test/run-pass/foreign-fn-linkname.rs
src/test/run-pass/foreign-no-abi.rs
src/test/run-pass/invoke-external-foreign.rs
src/test/run-pass/issue-2214.rs
src/test/run-pass/newtype-struct-with-dtor.rs
src/test/run-pass/pub-extern-privacy.rs
src/test/run-pass/regions-mock-trans.rs
src/test/run-pass/static-mut-foreign.rs
src/test/run-pass/struct-return.rs
src/test/run-pass/x86stdcall2.rs

index d1aa793e5fc1b83d0501baea22f99cbf542b66c8..278273b16719321c17b5be3445f140ec12e1a5c5 100644 (file)
@@ -19,6 +19,7 @@ extern {
     fn snappy_max_compressed_length(source_length: size_t) -> size_t;
 }
 
+#[fixed_stack_segment]
 fn main() {
     let x = unsafe { snappy_max_compressed_length(100) };
     println(fmt!("max compressed length of a 100 byte buffer: %?", x));
@@ -35,6 +36,11 @@ interfaces that aren't thread-safe, and almost any function that takes a pointer
 valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
 Rust's safe memory model.
 
+Finally, the `#[fixed_stack_segment]` annotation that appears on
+`main()` instructs the Rust compiler that when `main()` executes, it
+should request a "very large" stack segment.  More details on
+stack management can be found in the following sections.
+
 When declaring the argument types to a foreign function, the Rust compiler will not check if the
 declaration is correct, so specifying it correctly is part of keeping the binding correct at
 runtime.
@@ -75,6 +81,8 @@ length is number of elements currently contained, and the capacity is the total
 the allocated memory. The length is less than or equal to the capacity.
 
 ~~~~ {.xfail-test}
+#[fixed_stack_segment]
+#[inline(never)]
 pub fn validate_compressed_buffer(src: &[u8]) -> bool {
     unsafe {
         snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
@@ -86,6 +94,36 @@ The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, b
 guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
 signature.
 
+The `validate_compressed_buffer` wrapper is also annotated with two
+attributes `#[fixed_stack_segment]` and `#[inline(never)]`. The
+purpose of these attributes is to guarantee that there will be
+sufficient stack for the C function to execute. This is necessary
+because Rust, unlike C, does not assume that the stack is allocated in
+one continuous chunk. Instead, we rely on a *segmented stack* scheme,
+in which the stack grows and shrinks as necessary.  C code, however,
+expects one large stack, and so callers of C functions must request a
+large stack segment to ensure that the C routine will not run off the
+end of the stack.
+
+The compiler includes a lint mode that will report an error if you
+call a C function without a `#[fixed_stack_segment]` attribute. More
+details on the lint mode are given in a later section.
+
+You may be wondering why we include a `#[inline(never)]` directive.
+This directive informs the compiler never to inline this function.
+While not strictly necessary, it is usually a good idea to use an
+`#[inline(never)]` directive in concert with `#[fixed_stack_segment]`.
+The reason is that if a fn annotated with `fixed_stack_segment` is
+inlined, then its caller also inherits the `fixed_stack_segment`
+annotation. This means that rather than requesting a large stack
+segment only for the duration of the call into C, the large stack
+segment would be used for the entire duration of the caller. This is
+not necessarily *bad* -- it can for example be more efficient,
+particularly if `validate_compressed_buffer()` is called multiple
+times in a row -- but it does work against the purpose of the
+segmented stack scheme, which is to keep stacks small and thus
+conserve address space.
+
 The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
 allocated to hold the output too.
 
@@ -96,6 +134,8 @@ the true length after compression for setting the length.
 
 ~~~~ {.xfail-test}
 pub fn compress(src: &[u8]) -> ~[u8] {
+    #[fixed_stack_segment]; #[inline(never)];
+    
     unsafe {
         let srclen = src.len() as size_t;
         let psrc = vec::raw::to_ptr(src);
@@ -116,6 +156,8 @@ format and `snappy_uncompressed_length` will retrieve the exact buffer size requ
 
 ~~~~ {.xfail-test}
 pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
+    #[fixed_stack_segment]; #[inline(never)];
+    
     unsafe {
         let srclen = src.len() as size_t;
         let psrc = vec::raw::to_ptr(src);
@@ -139,6 +181,99 @@ pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
 For reference, the examples used here are also available as an [library on
 GitHub](https://github.com/thestinger/rust-snappy).
 
+# Automatic wrappers
+
+Sometimes writing Rust wrappers can be quite tedious.  For example, if
+function does not take any pointer arguments, often there is no need
+for translating types. In such cases, it is usually still a good idea
+to have a Rust wrapper so as to manage the segmented stacks, but you
+can take advantage of the (standard) `externfn!` macro to remove some
+of the tedium.
+
+In the initial section, we showed an extern block that added a call
+to a specific snappy API:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+#[link_args = "-lsnappy"]
+extern {
+    fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+}
+
+#[fixed_stack_segment]
+fn main() {
+    let x = unsafe { snappy_max_compressed_length(100) };
+    println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+To avoid the need to create a wrapper fn for `snappy_max_compressed_length()`,
+and also to avoid the need to think about `#[fixed_stack_segment]`, we
+could simply use the `externfn!` macro instead, as shown here:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+externfn!(#[link_args = "-lsnappy"]
+          fn snappy_max_compressed_length(source_length: size_t) -> size_t)
+
+fn main() {
+    let x = unsafe { snappy_max_compressed_length(100) };
+    println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+As you can see from the example, `externfn!` replaces the extern block
+entirely. After macro expansion, it will create something like this:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+// Automatically generated by
+//   externfn!(#[link_args = "-lsnappy"]
+//             fn snappy_max_compressed_length(source_length: size_t) -> size_t)
+unsafe fn snappy_max_compressed_length(source_length: size_t) -> size_t {
+    #[fixed_stack_segment]; #[inline(never)];
+    return snappy_max_compressed_length(source_length);
+    
+    #[link_args = "-lsnappy"]
+    extern {
+        fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+    }
+}
+
+fn main() {
+    let x = unsafe { snappy_max_compressed_length(100) };
+    println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+# Segmented stacks and the linter
+
+By default, whenever you invoke a non-Rust fn, the `cstack` lint will
+check that one of the following conditions holds:
+
+1. The call occurs inside of a fn that has been annotated with
+   `#[fixed_stack_segment]`;
+2. The call occurs inside of an `extern fn`;
+3. The call occurs within a stack closure created by some other
+   safe fn.
+   
+All of these conditions ensure that you are running on a large stack
+segmented. However, they are sometimes too strict. If your application
+will be making many calls into C, it is often beneficial to promote
+the `#[fixed_stack_segment]` attribute higher up the call chain.  For
+example, the Rust compiler actually labels main itself as requiring a
+`#[fixed_stack_segment]`. In such cases, the linter is just an
+annoyance, because all C calls that occur from within the Rust
+compiler are made on a large stack. Another situation where this
+frequently occurs is on a 64-bit architecture, where large stacks are
+the default. In cases, you can disable the linter by including a
+`#[allow(cstack)]` directive somewhere, which permits violations of
+the "cstack" rules given above (you can also use `#[warn(cstack)]` to
+convert the errors into warnings, if you prefer).
+
 # Destructors
 
 Foreign libraries often hand off ownership of resources to the calling code,
@@ -161,6 +296,9 @@ pub struct Unique<T> {
 
 impl<T: Send> Unique<T> {
     pub fn new(value: T) -> Unique<T> {
+        #[fixed_stack_segment];
+        #[inline(never)];
+        
         unsafe {
             let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T;
             assert!(!ptr::is_null(ptr));
@@ -184,6 +322,9 @@ impl<T: Send> Unique<T> {
 #[unsafe_destructor]
 impl<T: Send> Drop for Unique<T> {
     fn drop(&self) {
+        #[fixed_stack_segment];
+        #[inline(never)];
+        
         unsafe {
             let x = intrinsics::init(); // dummy value to swap in
             // moving the object out is needed to call the destructor
index e656360aa5a793c859d2059d284ad43131e0b681..9e1504aad2a5625ebda57cb59fd429ff3153f92f 100644 (file)
@@ -155,12 +155,20 @@ mod tests {
     use std::libc;
 
     fn malloc(n: size_t) -> CVec<u8> {
+        #[fixed_stack_segment];
+        #[inline(never)];
+
         unsafe {
             let mem = libc::malloc(n);
 
             assert!(mem as int != 0);
 
-            c_vec_with_dtor(mem as *mut u8, n as uint, || free(mem))
+            return c_vec_with_dtor(mem as *mut u8, n as uint, || f(mem));
+        }
+
+        fn f(mem: *c_void) {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe { libc::free(mem) }
         }
     }
 
index ed8cbcd0663f3f9874afc34e6ef92a827c76eeae..530885001292c51d77d5b0df33ba1cb21c42d452 100644 (file)
@@ -47,6 +47,8 @@ pub fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
 static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
 
 fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+    #[fixed_stack_segment]; #[inline(never)];
+
     do bytes.as_imm_buf |b, len| {
         unsafe {
             let mut outsz : size_t = 0;
@@ -73,6 +75,8 @@ pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
 }
 
 fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+    #[fixed_stack_segment]; #[inline(never)];
+
     do bytes.as_imm_buf |b, len| {
         unsafe {
             let mut outsz : size_t = 0;
index ead1f276ca701a13c9b3c0fbf08e21bd4685de9c..db87cf94641bb59290ffb1b3fb598db6426caee7 100644 (file)
 pub mod rustrt {
     use std::libc::{c_char, c_int};
 
-    extern {
-        pub fn linenoise(prompt: *c_char) -> *c_char;
-        pub fn linenoiseHistoryAdd(line: *c_char) -> c_int;
-        pub fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
-        pub fn linenoiseHistorySave(file: *c_char) -> c_int;
-        pub fn linenoiseHistoryLoad(file: *c_char) -> c_int;
-        pub fn linenoiseSetCompletionCallback(callback: *u8);
-        pub fn linenoiseAddCompletion(completions: *(), line: *c_char);
+    #[cfg(stage0)]
+    mod macro_hack {
+    #[macro_escape];
+    macro_rules! externfn(
+        (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+            extern {
+                fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+            }
+        )
+    )
     }
+
+    externfn!(fn linenoise(prompt: *c_char) -> *c_char)
+    externfn!(fn linenoiseHistoryAdd(line: *c_char) -> c_int)
+    externfn!(fn linenoiseHistorySetMaxLen(len: c_int) -> c_int)
+    externfn!(fn linenoiseHistorySave(file: *c_char) -> c_int)
+    externfn!(fn linenoiseHistoryLoad(file: *c_char) -> c_int)
+    externfn!(fn linenoiseSetCompletionCallback(callback: *u8))
+    externfn!(fn linenoiseAddCompletion(completions: *(), line: *c_char))
 }
 
 /// Add a line to history
@@ -84,7 +94,7 @@ pub unsafe fn complete(cb: CompletionCb) {
                         rustrt::linenoiseAddCompletion(completions, buf);
                     }
                 }
-}
+            }
         }
     }
 
index 9778248f005423468d2f4e1d46ae60d65e3ce687..75d00f9ea5999cdf2793c32d89f386bee73fa27f 100644 (file)
@@ -188,6 +188,8 @@ fn optgroups() -> ~[getopts::groups::OptGroup] {
 }
 
 fn usage(binary: &str, helpstr: &str) -> ! {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let message = fmt!("Usage: %s [OPTIONS] [FILTER]", binary);
     println(groups::usage(message, optgroups()));
     println("");
index 1e7b52daab3e4142a37d19d0a39cfc132ec1c422..ab35bf2386ca4d89ed9345c7004ff4a2f5ce182f 100644 (file)
@@ -64,6 +64,8 @@ fn lt(&self, other: &Timespec) -> bool {
  * nanoseconds since 1970-01-01T00:00:00Z.
  */
 pub fn get_time() -> Timespec {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         let mut sec = 0i64;
         let mut nsec = 0i32;
@@ -78,6 +80,8 @@ pub fn get_time() -> Timespec {
  * in nanoseconds since an unspecified epoch.
  */
 pub fn precise_time_ns() -> u64 {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         let mut ns = 0u64;
         rustrt::precise_time_ns(&mut ns);
@@ -95,6 +99,8 @@ pub fn precise_time_s() -> float {
 }
 
 pub fn tzset() {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         rustrt::rust_tzset();
     }
@@ -135,6 +141,8 @@ pub fn empty_tm() -> Tm {
 
 /// Returns the specified time in UTC
 pub fn at_utc(clock: Timespec) -> Tm {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         let Timespec { sec, nsec } = clock;
         let mut tm = empty_tm();
@@ -150,6 +158,8 @@ pub fn now_utc() -> Tm {
 
 /// Returns the specified time in the local timezone
 pub fn at(clock: Timespec) -> Tm {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         let Timespec { sec, nsec } = clock;
         let mut tm = empty_tm();
@@ -176,6 +186,8 @@ pub fn strftime(format: &str, tm: &Tm) -> ~str {
 impl Tm {
     /// Convert time to the seconds from January 1, 1970
     pub fn to_timespec(&self) -> Timespec {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             let sec = match self.tm_gmtoff {
                 0_i32 => rustrt::rust_timegm(self),
index b8f81a44759cecfaf4bd90fc8b979e8f84c8f79e..d010f7d52d8a82dc05dd2c996f5b7b7c53f82922 100644 (file)
@@ -229,6 +229,8 @@ fn usage() {
 }
 
 pub fn main() {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let os_args = os::args();
 
     if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) {
index 828c01157682a3c37b66268537c30c5a5c3b4d32..cdafb7400e1a294e4e6fd9c3061f56bc64ed2fe7 100644 (file)
@@ -645,9 +645,13 @@ pub fn build_session_options(binary: @str,
         }
         debugging_opts |= this_bit;
     }
+
     if debugging_opts & session::debug_llvm != 0 {
-        unsafe {
-            llvm::LLVMSetDebug(1);
+        set_llvm_debug();
+
+        fn set_llvm_debug() {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe { llvm::LLVMSetDebug(1); }
         }
     }
 
index b9e4e3da9200e8ba347a6efda36b328977d93b88..9175c13c8aeebbd2940d143aef154ac4980ff163 100644 (file)
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// LLVM wrappers are intended to be called from trans,
+// which already runs in a #[fixed_stack_segment]
+#[allow(cstack)];
+
 use std::c_str::ToCStr;
 use std::hashmap::HashMap;
 use std::libc::{c_uint, c_ushort};
index eb5e47959489daff0cc61c85c90f791434437e19..8837a9461edf4792bf0988af8c28ccc9fa38123e 100644 (file)
@@ -19,6 +19,7 @@
 use middle::lint;
 use middle::ty;
 use syntax::ast;
+use syntax::ast_map;
 use syntax::attr;
 use syntax::codemap::span;
 use visit = syntax::oldvisit;
@@ -47,19 +48,33 @@ pub fn stack_check_crate(tcx: ty::ctxt,
 
 fn stack_check_item(item: @ast::item,
                     (in_cx, v): (Context, visit::vt<Context>)) {
-    let safe_stack = match item.node {
+    match item.node {
+        ast::item_fn(_, ast::extern_fn, _, _, _) => {
+            // an extern fn is already being called from C code...
+            let new_cx = Context {safe_stack: true, ..in_cx};
+            visit::visit_item(item, (new_cx, v));
+        }
         ast::item_fn(*) => {
-            attr::contains_name(item.attrs, "fixed_stack_segment")
+            let safe_stack = fixed_stack_segment(item.attrs);
+            let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+            visit::visit_item(item, (new_cx, v));
+        }
+        ast::item_impl(_, _, _, ref methods) => {
+            // visit_method() would make this nicer
+            for &method in methods.iter() {
+                let safe_stack = fixed_stack_segment(method.attrs);
+                let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+                visit::visit_method_helper(method, (new_cx, v));
+            }
         }
         _ => {
-            false
+            visit::visit_item(item, (in_cx, v));
         }
-    };
-    let new_cx = Context {
-        tcx: in_cx.tcx,
-        safe_stack: safe_stack
-    };
-    visit::visit_item(item, (new_cx, v));
+    }
+
+    fn fixed_stack_segment(attrs: &[ast::Attribute]) -> bool {
+        attr::contains_name(attrs, "fixed_stack_segment")
+    }
 }
 
 fn stack_check_fn<'a>(fk: &visit::fn_kind,
@@ -69,13 +84,23 @@ fn stack_check_fn<'a>(fk: &visit::fn_kind,
                       id: ast::NodeId,
                       (in_cx, v): (Context, visit::vt<Context>)) {
     let safe_stack = match *fk {
-        visit::fk_item_fn(*) => in_cx.safe_stack, // see stack_check_item above
-        visit::fk_anon(*) | visit::fk_fn_block | visit::fk_method(*) => false,
-    };
-    let new_cx = Context {
-        tcx: in_cx.tcx,
-        safe_stack: safe_stack
+        visit::fk_method(*) | visit::fk_item_fn(*) => {
+            in_cx.safe_stack // see stack_check_item above
+        }
+        visit::fk_anon(*) | visit::fk_fn_block => {
+            match ty::get(ty::node_id_to_type(in_cx.tcx, id)).sty {
+                ty::ty_bare_fn(*) |
+                ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) |
+                ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
+                    false
+                }
+                _ => {
+                    in_cx.safe_stack
+                }
+            }
+        }
     };
+    let new_cx = Context {safe_stack: safe_stack, ..in_cx};
     debug!("stack_check_fn(safe_stack=%b, id=%?)", safe_stack, id);
     visit::visit_fn(fk, decl, body, sp, id, (new_cx, v));
 }
@@ -92,12 +117,7 @@ fn stack_check_expr<'a>(expr: @ast::expr,
                 match ty::get(callee_ty).sty {
                     ty::ty_bare_fn(ref fty) => {
                         if !fty.abis.is_rust() && !fty.abis.is_intrinsic() {
-                            cx.tcx.sess.add_lint(
-                                lint::cstack,
-                                callee.id,
-                                callee.span,
-                                fmt!("invoking non-Rust fn in fn without \
-                                      #[fixed_stack_segment]"));
+                            call_to_extern_fn(cx, callee);
                         }
                     }
                     _ => {}
@@ -108,3 +128,32 @@ fn stack_check_expr<'a>(expr: @ast::expr,
     }
     visit::visit_expr(expr, (cx, v));
 }
+
+fn call_to_extern_fn(cx: Context, callee: @ast::expr) {
+    // Permit direct calls to extern fns that are annotated with
+    // #[rust_stack]. This is naturally a horrible pain to achieve.
+    match callee.node {
+        ast::expr_path(*) => {
+            match cx.tcx.def_map.find(&callee.id) {
+                Some(&ast::def_fn(id, _)) if id.crate == ast::LOCAL_CRATE => {
+                    match cx.tcx.items.find(&id.node) {
+                        Some(&ast_map::node_foreign_item(item, _, _, _)) => {
+                            if attr::contains_name(item.attrs, "rust_stack") {
+                                return;
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+                _ => {}
+            }
+        }
+        _ => {}
+    }
+
+    cx.tcx.sess.add_lint(lint::cstack,
+                         callee.id,
+                         callee.span,
+                         fmt!("invoking non-Rust fn in fn without \
+                              #[fixed_stack_segment]"));
+}
index 6189d28b0ed088a7c49f04449ce15e2fea732101..88fc02ca83c66f34abced2d083e0c9bb0b901a8b 100644 (file)
@@ -2509,14 +2509,14 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
                     register_method(ccx, id, pth, m)
                 }
 
-                ast_map::node_foreign_item(ni, _, _, pth) => {
+                ast_map::node_foreign_item(ni, abis, _, pth) => {
                     let ty = ty::node_id_to_type(ccx.tcx, ni.id);
                     exprt = true;
 
                     match ni.node {
                         ast::foreign_item_fn(*) => {
                             let path = vec::append((*pth).clone(), [path_name(ni.ident)]);
-                            foreign::register_foreign_item_fn(ccx, abis, &path, ni);
+                            foreign::register_foreign_item_fn(ccx, abis, &path, ni)
                         }
                         ast::foreign_item_static(*) => {
                             let ident = token::ident_to_str(&ni.ident);
index 0bf0a74b2f43b764bfa262cf2d714e9dbe885282..f9cbab58211e6475296a4db16e6207c6fa6a49b6 100644 (file)
 #[license = "MIT/ASL2"];
 #[crate_type = "lib"];
 
+// Rustc tasks always run on a fixed_stack_segment, so code in this
+// module can call C functions (in particular, LLVM functions) with
+// impunity.
+#[allow(cstack)];
+
 extern mod extra;
 extern mod syntax;
 
index 10c6832e08714f36cb870c2debdc81b826e3aa80..d4bee13aae7f97eb3a180a150eebfd59c5f52239 100644 (file)
@@ -498,6 +498,8 @@ pub fn run_line(repl: &mut Repl, input: @io::Reader, out: @io::Writer, line: ~st
 }
 
 pub fn main() {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let args = os::args();
     let input = io::stdin();
     let out = io::stdout();
index 82f098b668dc45d1dbd424e6f56816c3496c4427..41c1c7e31aeff82eb7503c354e1ee3af0dc647c1 100644 (file)
@@ -382,6 +382,8 @@ pub fn find_and_install_dependencies(ctxt: &Ctx,
 
 #[cfg(windows)]
 pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
+    #[fixed_stack_segment]; #[inline(never)];
+
     /* FIXME (#1768): Investigate how to do this on win32
        Node wraps symlinks by having a .bat,
        but that won't work with minGW. */
@@ -394,6 +396,8 @@ pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
 #[cfg(target_os = "freebsd")]
 #[cfg(target_os = "macos")]
 pub fn link_exe(src: &Path, dest: &Path) -> bool {
+    #[fixed_stack_segment]; #[inline(never)];
+
     use std::c_str::ToCStr;
     use std::libc;
 
index 6fc14439abb24e1a59030c770c5213522677fd23..98710c158e0d7f8d82e0719952ab13716a075e51 100644 (file)
@@ -96,6 +96,7 @@ pub fn owns_buffer(&self) -> bool {
     ///
     /// Fails if the CString is null.
     pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
+        #[fixed_stack_segment]; #[inline(never)];
         if self.buf.is_null() { fail!("CString is null!"); }
         unsafe {
             let len = libc::strlen(self.buf) as uint;
@@ -114,6 +115,7 @@ pub fn iter<'a>(&'a self) -> CStringIterator<'a> {
 
 impl Drop for CString {
     fn drop(&self) {
+        #[fixed_stack_segment]; #[inline(never)];
         if self.owns_buffer_ {
             unsafe {
                 libc::free(self.buf as *libc::c_void)
@@ -172,6 +174,7 @@ unsafe fn to_c_str_unchecked(&self) -> CString {
 
 impl<'self> ToCStr for &'self [u8] {
     fn to_c_str(&self) -> CString {
+        #[fixed_stack_segment]; #[inline(never)];
         let mut cs = unsafe { self.to_c_str_unchecked() };
         do cs.with_mut_ref |buf| {
             for i in range(0, self.len()) {
@@ -190,6 +193,7 @@ fn to_c_str(&self) -> CString {
     }
 
     unsafe fn to_c_str_unchecked(&self) -> CString {
+        #[fixed_stack_segment]; #[inline(never)];
         do self.as_imm_buf |self_buf, self_len| {
             let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
             if buf.is_null() {
@@ -260,12 +264,16 @@ fn test_is_null() {
 
     #[test]
     fn test_unwrap() {
+        #[fixed_stack_segment]; #[inline(never)];
+
         let c_str = "hello".to_c_str();
         unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
     }
 
     #[test]
     fn test_with_ref() {
+        #[fixed_stack_segment]; #[inline(never)];
+
         let c_str = "hello".to_c_str();
         let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
         assert!(!c_str.is_null());
index e51bd4a16b6922d1d5c7a015e30a08b0c97d973e..8f5a3728e95b4845f2ce6de11e0fbf39ced394b8 100644 (file)
@@ -928,6 +928,8 @@ fn convert_whence(whence: SeekStyle) -> i32 {
 
 impl Reader for *libc::FILE {
     fn read(&self, bytes: &mut [u8], len: uint) -> uint {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             do bytes.as_mut_buf |buf_p, buf_len| {
                 assert!(buf_len >= len);
@@ -950,16 +952,22 @@ fn read(&self, bytes: &mut [u8], len: uint) -> uint {
         }
     }
     fn read_byte(&self) -> int {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             libc::fgetc(*self) as int
         }
     }
     fn eof(&self) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             return libc::feof(*self) != 0 as c_int;
         }
     }
     fn seek(&self, offset: int, whence: SeekStyle) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             assert!(libc::fseek(*self,
                                      offset as c_long,
@@ -967,6 +975,8 @@ fn seek(&self, offset: int, whence: SeekStyle) {
         }
     }
     fn tell(&self) -> uint {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             return libc::ftell(*self) as uint;
         }
@@ -1005,6 +1015,8 @@ pub fn new(f: *libc::FILE) -> FILERes {
 
 impl Drop for FILERes {
     fn drop(&self) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             libc::fclose(self.f);
         }
@@ -1035,12 +1047,16 @@ pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> @Reader {
 * ~~~
 */
 pub fn stdin() -> @Reader {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         @rustrt::rust_get_stdin() as @Reader
     }
 }
 
 pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let f = do path.with_c_str |pathbuf| {
         do "rb".with_c_str |modebuf| {
             unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) }
@@ -1162,6 +1178,8 @@ fn get_type(&self) -> WriterType { File }
 
 impl Writer for *libc::FILE {
     fn write(&self, v: &[u8]) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             do v.as_imm_buf |vbuf, len| {
                 let nout = libc::fwrite(vbuf as *c_void,
@@ -1177,6 +1195,8 @@ fn write(&self, v: &[u8]) {
         }
     }
     fn seek(&self, offset: int, whence: SeekStyle) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             assert!(libc::fseek(*self,
                                      offset as c_long,
@@ -1184,16 +1204,22 @@ fn seek(&self, offset: int, whence: SeekStyle) {
         }
     }
     fn tell(&self) -> uint {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             libc::ftell(*self) as uint
         }
     }
     fn flush(&self) -> int {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             libc::fflush(*self) as int
         }
     }
     fn get_type(&self) -> WriterType {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             let fd = libc::fileno(*self);
             if libc::isatty(fd) == 0 { File   }
@@ -1212,6 +1238,8 @@ pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> @Writer {
 
 impl Writer for fd_t {
     fn write(&self, v: &[u8]) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             let mut count = 0u;
             do v.as_imm_buf |vbuf, len| {
@@ -1238,6 +1266,8 @@ fn tell(&self) -> uint {
     }
     fn flush(&self) -> int { 0 }
     fn get_type(&self) -> WriterType {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             if libc::isatty(*self) == 0 { File } else { Screen }
         }
@@ -1256,6 +1286,8 @@ pub fn new(fd: fd_t) -> FdRes {
 
 impl Drop for FdRes {
     fn drop(&self) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             libc::close(self.fd);
         }
@@ -1273,6 +1305,8 @@ pub fn fd_writer(fd: fd_t, cleanup: bool) -> @Writer {
 
 pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
                    -> Result<@Writer, ~str> {
+    #[fixed_stack_segment]; #[inline(never)];
+
     #[cfg(windows)]
     fn wb() -> c_int {
       (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
@@ -1573,6 +1607,8 @@ pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> {
 
 // FIXME: fileflags // #2004
 pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         let f = do path.with_c_str |pathbuf| {
             do "w".with_c_str |modebuf| {
@@ -1803,12 +1839,13 @@ pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>,
                          blk: &fn(v: Res<*libc::FILE>)) {
         blk(Res::new(Arg {
             val: file.f, opt_level: opt_level,
-            fsync_fn: |file, l| {
-                unsafe {
-                    os::fsync_fd(libc::fileno(*file), l) as int
-                }
-            }
+            fsync_fn: |file, l| fsync_fd(fileno(*file), l)
         }));
+
+        fn fileno(stream: *libc::FILE) -> libc::c_int {
+            #[fixed_stack_segment]; #[inline(never)];
+            unsafe { libc::fileno(stream) }
+        }
     }
 
     // fsync fd after executing blk
@@ -1816,10 +1853,16 @@ pub fn fd_res_sync(fd: &FdRes, opt_level: Option<Level>,
                        blk: &fn(v: Res<fd_t>)) {
         blk(Res::new(Arg {
             val: fd.fd, opt_level: opt_level,
-            fsync_fn: |fd, l| os::fsync_fd(*fd, l) as int
+            fsync_fn: |fd, l| fsync_fd(*fd, l)
         }));
     }
 
+    fn fsync_fd(fd: libc::c_int, level: Level) -> int {
+        #[fixed_stack_segment]; #[inline(never)];
+
+        os::fsync_fd(fd, level) as int
+    }
+
     // Type of objects that may want to fsync
     pub trait FSyncable { fn fsync(&self, l: Level) -> int; }
 
index 678704fe0983308ee45bd5a6afbc051f76834721..d3e0c88e5dff7e78bad2ed3543178ca89767ebd3 100644 (file)
@@ -2762,9 +2762,11 @@ pub mod dirent {
             // doesn't link it correctly on i686, so we're going
             // through a C function that mysteriously does work.
             pub unsafe fn opendir(dirname: *c_char) -> *DIR {
+                #[fixed_stack_segment]; #[inline(never)];
                 rust_opendir(dirname)
             }
             pub unsafe fn readdir(dirp: *DIR) -> *dirent_t {
+                #[fixed_stack_segment]; #[inline(never)];
                 rust_readdir(dirp)
             }
 
index 52d5f835fe63d4fe1027efea4e1d0b21dee497d9..17175de9b929dafd3025c0ca6b57102b5046f7fc 100644 (file)
@@ -41,7 +41,7 @@ mod delegated {
             use unstable::intrinsics;
 
             $(
-                #[inline]
+                #[inline] #[fixed_stack_segment] #[inline(never)]
                 pub fn $name($( $arg : $arg_ty ),*) -> $rv {
                     unsafe {
                         $bound_name($( $arg ),*)
index 60527905779f035296e8a126b7dfbe9b037677a0..91361a61c215137042e4607715c08415094f96b8 100644 (file)
@@ -43,7 +43,7 @@ mod delegated {
             use unstable::intrinsics;
 
             $(
-                #[inline]
+                #[inline] #[fixed_stack_segment] #[inline(never)]
                 pub fn $name($( $arg : $arg_ty ),*) -> $rv {
                     unsafe {
                         $bound_name($( $arg ),*)
index 3d6f541767ec7db0ab225c69a086015048ecec03..4e5a0e9b9138a632beda8eeaa6e4689cd585cfe2 100644 (file)
@@ -51,6 +51,7 @@
 
 /// Delegates to the libc close() function, returning the same return value.
 pub fn close(fd: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         libc::close(fd)
     }
@@ -70,6 +71,7 @@ pub mod rustrt {
 static BUF_BYTES : uint = 2048u;
 
 pub fn getcwd() -> Path {
+    #[fixed_stack_segment]; #[inline(never)];
     let mut buf = [0 as libc::c_char, ..BUF_BYTES];
     do buf.as_mut_buf |buf, len| {
         unsafe {
@@ -109,6 +111,8 @@ pub mod win32 {
 
     pub fn fill_utf16_buf_and_decode(f: &fn(*mut u16, DWORD) -> DWORD)
         -> Option<~str> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             let mut n = TMPBUF_SZ as DWORD;
             let mut res = None;
@@ -145,6 +149,18 @@ pub fn as_utf16_p<T>(s: &str, f: &fn(*u16) -> T) -> T {
     }
 }
 
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+    (fn $name:ident ()) => (
+        extern {
+            fn $name();
+        }
+    )
+)
+}
+
 /*
 Accessing environment variables is not generally threadsafe.
 Serialize access through a global lock.
@@ -161,12 +177,8 @@ fn with_env_lock<T>(f: &fn() -> T) -> T {
         };
     }
 
-    extern {
-        #[fast_ffi]
-        fn rust_take_env_lock();
-        #[fast_ffi]
-        fn rust_drop_env_lock();
-    }
+    externfn!(fn rust_take_env_lock());
+    externfn!(fn rust_drop_env_lock());
 }
 
 /// Returns a vector of (variable, value) pairs for all the environment
@@ -175,6 +187,8 @@ pub fn env() -> ~[(~str,~str)] {
     unsafe {
         #[cfg(windows)]
         unsafe fn get_env_pairs() -> ~[~str] {
+            #[fixed_stack_segment]; #[inline(never)];
+
             use libc::funcs::extra::kernel32::{
                 GetEnvironmentStringsA,
                 FreeEnvironmentStringsA
@@ -198,6 +212,8 @@ unsafe fn get_env_pairs() -> ~[~str] {
         }
         #[cfg(unix)]
         unsafe fn get_env_pairs() -> ~[~str] {
+            #[fixed_stack_segment]; #[inline(never)];
+
             extern {
                 fn rust_env_pairs() -> **libc::c_char;
             }
@@ -237,6 +253,7 @@ fn env_convert(input: ~[~str]) -> ~[(~str, ~str)] {
 /// Fetches the environment variable `n` from the current process, returning
 /// None if the variable isn't set.
 pub fn getenv(n: &str) -> Option<~str> {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         do with_env_lock {
             let s = do n.with_c_str |buf| {
@@ -255,6 +272,8 @@ pub fn getenv(n: &str) -> Option<~str> {
 /// Fetches the environment variable `n` from the current process, returning
 /// None if the variable isn't set.
 pub fn getenv(n: &str) -> Option<~str> {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         do with_env_lock {
             use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
@@ -272,6 +291,7 @@ pub fn getenv(n: &str) -> Option<~str> {
 /// Sets the environment variable `n` to the value `v` for the currently running
 /// process
 pub fn setenv(n: &str, v: &str) {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         do with_env_lock {
             do n.with_c_str |nbuf| {
@@ -288,6 +308,8 @@ pub fn setenv(n: &str, v: &str) {
 /// Sets the environment variable `n` to the value `v` for the currently running
 /// process
 pub fn setenv(n: &str, v: &str) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         do with_env_lock {
             use os::win32::as_utf16_p;
@@ -304,6 +326,7 @@ pub fn setenv(n: &str, v: &str) {
 pub fn unsetenv(n: &str) {
     #[cfg(unix)]
     fn _unsetenv(n: &str) {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             do with_env_lock {
                 do n.with_c_str |nbuf| {
@@ -314,6 +337,7 @@ fn _unsetenv(n: &str) {
     }
     #[cfg(windows)]
     fn _unsetenv(n: &str) {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             do with_env_lock {
                 use os::win32::as_utf16_p;
@@ -328,6 +352,7 @@ fn _unsetenv(n: &str) {
 }
 
 pub fn fdopen(fd: c_int) -> *FILE {
+    #[fixed_stack_segment]; #[inline(never)];
     do "r".with_c_str |modebuf| {
         unsafe {
             libc::fdopen(fd, modebuf)
@@ -340,6 +365,7 @@ pub fn fdopen(fd: c_int) -> *FILE {
 
 #[cfg(windows)]
 pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         use libc::funcs::extra::msvcrt::*;
         return commit(fd);
@@ -349,6 +375,7 @@ pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
 #[cfg(target_os = "linux")]
 #[cfg(target_os = "android")]
 pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         use libc::funcs::posix01::unistd::*;
         match level {
@@ -361,6 +388,8 @@ pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
 
 #[cfg(target_os = "macos")]
 pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         use libc::consts::os::extra::*;
         use libc::funcs::posix88::fcntl::*;
@@ -381,6 +410,8 @@ pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
 
 #[cfg(target_os = "freebsd")]
 pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         use libc::funcs::posix01::unistd::*;
         return fsync(fd);
@@ -394,6 +425,7 @@ pub struct Pipe {
 
 #[cfg(unix)]
 pub fn pipe() -> Pipe {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         let mut fds = Pipe {input: 0 as c_int,
                             out: 0 as c_int };
@@ -406,6 +438,7 @@ pub fn pipe() -> Pipe {
 
 #[cfg(windows)]
 pub fn pipe() -> Pipe {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         // Windows pipes work subtly differently than unix pipes, and their
         // inheritance has to be handled in a different way that I do not
@@ -424,6 +457,7 @@ pub fn pipe() -> Pipe {
 }
 
 fn dup2(src: c_int, dst: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         libc::dup2(src, dst)
     }
@@ -440,6 +474,7 @@ pub fn self_exe_path() -> Option<Path> {
 
     #[cfg(target_os = "freebsd")]
     fn load_self() -> Option<~str> {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             use libc::funcs::bsd44::*;
             use libc::consts::os::extra::*;
@@ -458,6 +493,7 @@ fn load_self() -> Option<~str> {
     #[cfg(target_os = "linux")]
     #[cfg(target_os = "android")]
     fn load_self() -> Option<~str> {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             use libc::funcs::posix01::unistd::readlink;
 
@@ -479,6 +515,7 @@ fn load_self() -> Option<~str> {
 
     #[cfg(target_os = "macos")]
     fn load_self() -> Option<~str> {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             do fill_charp_buf() |buf, sz| {
                 let mut sz = sz as u32;
@@ -490,6 +527,7 @@ fn load_self() -> Option<~str> {
 
     #[cfg(windows)]
     fn load_self() -> Option<~str> {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             use os::win32::fill_utf16_buf_and_decode;
             do fill_utf16_buf_and_decode() |buf, sz| {
@@ -592,6 +630,7 @@ pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool {
 
 /// Indicates whether a path represents a directory
 pub fn path_is_dir(p: &Path) -> bool {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         do p.with_c_str |buf| {
             rustrt::rust_path_is_dir(buf) != 0 as c_int
@@ -601,6 +640,7 @@ pub fn path_is_dir(p: &Path) -> bool {
 
 /// Indicates whether a path exists
 pub fn path_exists(p: &Path) -> bool {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         do p.with_c_str |buf| {
             rustrt::rust_path_exists(buf) != 0 as c_int
@@ -633,6 +673,7 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool {
 
     #[cfg(windows)]
     fn mkdir(p: &Path, _mode: c_int) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             use os::win32::as_utf16_p;
             // FIXME: turn mode into something useful? #2623
@@ -645,6 +686,7 @@ fn mkdir(p: &Path, _mode: c_int) -> bool {
 
     #[cfg(unix)]
     fn mkdir(p: &Path, mode: c_int) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         do p.with_c_str |buf| {
             unsafe {
                 libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int)
@@ -689,6 +731,7 @@ pub fn list_dir(p: &Path) -> ~[~str] {
         #[cfg(target_os = "freebsd")]
         #[cfg(target_os = "macos")]
         unsafe fn get_list(p: &Path) -> ~[~str] {
+            #[fixed_stack_segment]; #[inline(never)];
             use libc::{dirent_t};
             use libc::{opendir, readdir, closedir};
             extern {
@@ -721,6 +764,7 @@ unsafe fn get_list(p: &Path) -> ~[~str] {
         }
         #[cfg(windows)]
         unsafe fn get_list(p: &Path) -> ~[~str] {
+            #[fixed_stack_segment]; #[inline(never)];
             use libc::consts::os::extra::INVALID_HANDLE_VALUE;
             use libc::{wcslen, free};
             use libc::funcs::extra::kernel32::{
@@ -809,6 +853,7 @@ pub fn remove_dir(p: &Path) -> bool {
 
     #[cfg(windows)]
     fn rmdir(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             use os::win32::as_utf16_p;
             return do as_utf16_p(p.to_str()) |buf| {
@@ -819,6 +864,7 @@ fn rmdir(p: &Path) -> bool {
 
     #[cfg(unix)]
     fn rmdir(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         do p.with_c_str |buf| {
             unsafe {
                 libc::rmdir(buf) == (0 as c_int)
@@ -834,6 +880,7 @@ pub fn change_dir(p: &Path) -> bool {
 
     #[cfg(windows)]
     fn chdir(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             use os::win32::as_utf16_p;
             return do as_utf16_p(p.to_str()) |buf| {
@@ -844,6 +891,7 @@ fn chdir(p: &Path) -> bool {
 
     #[cfg(unix)]
     fn chdir(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         do p.with_c_str |buf| {
             unsafe {
                 libc::chdir(buf) == (0 as c_int)
@@ -858,6 +906,7 @@ pub fn copy_file(from: &Path, to: &Path) -> bool {
 
     #[cfg(windows)]
     fn do_copy_file(from: &Path, to: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             use os::win32::as_utf16_p;
             return do as_utf16_p(from.to_str()) |fromp| {
@@ -871,6 +920,7 @@ fn do_copy_file(from: &Path, to: &Path) -> bool {
 
     #[cfg(unix)]
     fn do_copy_file(from: &Path, to: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             let istream = do from.with_c_str |fromp| {
                 do "rb".with_c_str |modebuf| {
@@ -933,6 +983,7 @@ pub fn remove_file(p: &Path) -> bool {
 
     #[cfg(windows)]
     fn unlink(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             use os::win32::as_utf16_p;
             return do as_utf16_p(p.to_str()) |buf| {
@@ -943,6 +994,7 @@ fn unlink(p: &Path) -> bool {
 
     #[cfg(unix)]
     fn unlink(p: &Path) -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             do p.with_c_str |buf| {
                 libc::unlink(buf) == (0 as c_int)
@@ -957,6 +1009,7 @@ pub fn errno() -> int {
     #[cfg(target_os = "macos")]
     #[cfg(target_os = "freebsd")]
     fn errno_location() -> *c_int {
+        #[fixed_stack_segment]; #[inline(never)];
         #[nolink]
         extern {
             fn __error() -> *c_int;
@@ -969,6 +1022,7 @@ fn errno_location() -> *c_int {
     #[cfg(target_os = "linux")]
     #[cfg(target_os = "android")]
     fn errno_location() -> *c_int {
+        #[fixed_stack_segment]; #[inline(never)];
         #[nolink]
         extern {
             fn __errno_location() -> *c_int;
@@ -986,6 +1040,7 @@ fn errno_location() -> *c_int {
 #[cfg(windows)]
 /// Returns the platform-specific value of errno
 pub fn errno() -> uint {
+    #[fixed_stack_segment]; #[inline(never)];
     use libc::types::os::arch::extra::DWORD;
 
     #[link_name = "kernel32"]
@@ -1008,6 +1063,8 @@ fn strerror() -> ~str {
         #[cfg(target_os = "freebsd")]
         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
                       -> c_int {
+            #[fixed_stack_segment]; #[inline(never)];
+
             #[nolink]
             extern {
                 fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
@@ -1023,6 +1080,7 @@ fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
         // So we just use __xpg_strerror_r which is always POSIX compliant
         #[cfg(target_os = "linux")]
         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
+            #[fixed_stack_segment]; #[inline(never)];
             #[nolink]
             extern {
                 fn __xpg_strerror_r(errnum: c_int,
@@ -1050,6 +1108,8 @@ fn __xpg_strerror_r(errnum: c_int,
 
     #[cfg(windows)]
     fn strerror() -> ~str {
+        #[fixed_stack_segment]; #[inline(never)];
+
         use libc::types::os::arch::extra::DWORD;
         use libc::types::os::arch::extra::LPSTR;
         use libc::types::os::arch::extra::LPVOID;
@@ -1129,6 +1189,8 @@ unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] {
  */
 #[cfg(target_os = "macos")]
 pub fn real_args() -> ~[~str] {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         let (argc, argv) = (*_NSGetArgc() as c_int,
                             *_NSGetArgv() as **c_char);
@@ -1150,6 +1212,8 @@ pub fn real_args() -> ~[~str] {
 
 #[cfg(windows)]
 pub fn real_args() -> ~[~str] {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let mut nArgs: c_int = 0;
     let lpArgCount: *mut c_int = &mut nArgs;
     let lpCmdLine = unsafe { GetCommandLineW() };
@@ -1232,6 +1296,8 @@ pub fn set_args(new_args: ~[~str]) {
 #[cfg(target_os = "freebsd")]
 #[cfg(target_os = "macos")]
 pub fn glob(pattern: &str) -> ~[Path] {
+    #[fixed_stack_segment]; #[inline(never)];
+
     #[cfg(target_os = "linux")]
     #[cfg(target_os = "android")]
     fn default_glob_t () -> libc::glob_t {
@@ -1326,6 +1392,8 @@ fn round_up(from: uint, to: uint) -> uint {
 
 #[cfg(unix)]
 pub fn page_size() -> uint {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         libc::sysconf(libc::_SC_PAGESIZE) as uint
     }
@@ -1333,6 +1401,8 @@ pub fn page_size() -> uint {
 
 #[cfg(windows)]
 pub fn page_size() -> uint {
+    #[fixed_stack_segment]; #[inline(never)];
+
   unsafe {
     let mut info = libc::SYSTEM_INFO::new();
     libc::GetSystemInfo(&mut info);
@@ -1404,6 +1474,8 @@ fn to_str(&self) -> ~str {
 #[cfg(unix)]
 impl MemoryMap {
     pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         use libc::off_t;
 
         let mut addr: *c_void = ptr::null();
@@ -1460,6 +1532,8 @@ pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError>
 #[cfg(unix)]
 impl Drop for MemoryMap {
     fn drop(&self) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             match libc::munmap(self.data as *c_void, self.len) {
                 0 => (),
@@ -1476,6 +1550,8 @@ fn drop(&self) {
 #[cfg(windows)]
 impl MemoryMap {
     pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
 
         let mut lpAddress: LPVOID = ptr::mut_null();
@@ -1569,6 +1645,8 @@ pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError>
 #[cfg(windows)]
 impl Drop for MemoryMap {
     fn drop(&self) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
 
         unsafe {
@@ -1921,6 +1999,8 @@ fn copy_file_does_not_exist() {
 
     #[test]
     fn copy_file_ok() {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             let tempdir = getcwd(); // would like to use $TMPDIR,
                                     // doesn't seem to work on Linux
@@ -1991,17 +2071,23 @@ fn memory_map_rw() {
 
     #[test]
     fn memory_map_file() {
+        #[fixed_stack_segment]; #[inline(never)];
+
         use result::{Ok, Err};
         use os::*;
         use libc::*;
 
         #[cfg(unix)]
+        #[fixed_stack_segment]
+        #[inline(never)]
         fn lseek_(fd: c_int, size: uint) {
             unsafe {
                 assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
             }
         }
         #[cfg(windows)]
+        #[fixed_stack_segment]
+        #[inline(never)]
         fn lseek_(fd: c_int, size: uint) {
            unsafe {
                assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
index de7658b5710b32cded88809f57693383a8896b5e..858098409e90d7c8dd9f4ff76e185a38fb107f64 100644 (file)
@@ -381,6 +381,7 @@ pub fn default_stat() -> libc::stat {
 #[cfg(target_os = "win32")]
 impl WindowsPath {
     pub fn stat(&self) -> Option<libc::stat> {
+        #[fixed_stack_segment]; #[inline(never)];
         do self.with_c_str |buf| {
             let mut st = stat::arch::default_stat();
             match unsafe { libc::stat(buf, &mut st) } {
@@ -415,6 +416,7 @@ pub fn get_mode(&self) -> Option<uint> {
 #[cfg(not(target_os = "win32"))]
 impl PosixPath {
     pub fn stat(&self) -> Option<libc::stat> {
+        #[fixed_stack_segment]; #[inline(never)];
         do self.with_c_str |buf| {
             let mut st = stat::arch::default_stat();
             match unsafe { libc::stat(buf as *libc::c_char, &mut st) } {
@@ -493,6 +495,7 @@ pub fn get_ctime(&self) -> Option<(i64, int)> {
 #[cfg(unix)]
 impl PosixPath {
     pub fn lstat(&self) -> Option<libc::stat> {
+        #[fixed_stack_segment]; #[inline(never)];
         do self.with_c_str |buf| {
             let mut st = stat::arch::default_stat();
             match unsafe { libc::lstat(buf, &mut st) } {
@@ -1101,6 +1104,8 @@ pub fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> {
     }
 
     pub fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             if (s.len() > 1 &&
                 libc::isalpha(s[0] as libc::c_int) != 0 &&
index 35c7380e3117c02c979960282bf4821d03939b5a..7b10866207a4222a6f6426b044384673fa09a940 100644 (file)
@@ -877,6 +877,8 @@ fn next(&mut self) -> u32 {
 impl XorShiftRng {
     /// Create an xor shift random number generator with a random seed.
     pub fn new() -> XorShiftRng {
+        #[fixed_stack_segment]; #[inline(never)];
+
         // generate seeds the same way as seed(), except we have a spceific size
         let mut s = [0u8, ..16];
         loop {
@@ -910,6 +912,8 @@ pub fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng {
 
 /// Create a new random seed.
 pub fn seed() -> ~[u8] {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         let n = rustrt::rand_seed_size() as uint;
         let mut s = vec::from_elem(n, 0_u8);
@@ -1142,6 +1146,8 @@ fn test_random() {
 
     #[test]
     fn compare_isaac_implementation() {
+        #[fixed_stack_segment]; #[inline(never)];
+
         // This is to verify that the implementation of the ISAAC rng is
         // correct (i.e. matches the output of the upstream implementation,
         // which is in the runtime)
index 6f26e3bd9efe8d76c934b06e32a8db27772176f3..71eae56c894b81842baf946b38ac56ad610c688c 100644 (file)
@@ -118,12 +118,22 @@ unsafe fn load_argc_and_argv(argc: int, argv: **u8) -> ~[~str] {
         args
     }
 
-    extern {
-        fn rust_take_global_args_lock();
-        fn rust_drop_global_args_lock();
-        fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>;
+    #[cfg(stage0)]
+    mod macro_hack {
+    #[macro_escape];
+    macro_rules! externfn(
+        (fn $name:ident () $(-> $ret_ty:ty),*) => (
+            extern {
+                fn $name() $(-> $ret_ty),*;
+            }
+        )
+    )
     }
 
+    externfn!(fn rust_take_global_args_lock())
+    externfn!(fn rust_drop_global_args_lock())
+    externfn!(fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>)
+
     #[cfg(test)]
     mod tests {
         use option::{Some, None};
index ba4cbc668038fcec80364da26d167f7ae5e762cd..6400c1b660d17f7421bac367c7d5eac0e5d34584 100644 (file)
@@ -136,6 +136,7 @@ fn write_hex(&self, mut i: uint) {
     }
 
     unsafe fn write_cstr(&self, p: *c_char) {
+        #[fixed_stack_segment]; #[inline(never)];
         use libc::strlen;
         use vec;
 
index 7488b08da42c5d9777f1158e452bb446ec9ebe85..7d3f5f917748732982753722828c78349eaee010 100644 (file)
@@ -35,8 +35,9 @@ fn align_to(size: uint, align: uint) -> uint {
 }
 
 /// A wrapper around libc::malloc, aborting on out-of-memory
-#[inline]
 pub unsafe fn malloc_raw(size: uint) -> *c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let p = malloc(size as size_t);
     if p.is_null() {
         // we need a non-allocating way to print an error here
@@ -46,8 +47,9 @@ pub unsafe fn malloc_raw(size: uint) -> *c_void {
 }
 
 /// A wrapper around libc::realloc, aborting on out-of-memory
-#[inline]
 pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let p = realloc(ptr, size as size_t);
     if p.is_null() {
         // we need a non-allocating way to print an error here
@@ -97,8 +99,9 @@ pub unsafe fn exchange_free_(ptr: *c_char) {
     exchange_free(ptr)
 }
 
-#[inline]
 pub unsafe fn exchange_free(ptr: *c_char) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     free(ptr as *c_void);
 }
 
index 8715e768e32767a72e960c7e08826a1cb6256716..bca1b4a70f4c933ba604d15f117255bb593251e3 100644 (file)
@@ -37,6 +37,7 @@ pub struct LocalHeap {
 }
 
 impl LocalHeap {
+    #[fixed_stack_segment] #[inline(never)]
     pub fn new() -> LocalHeap {
         unsafe {
             // Don't need synchronization for the single-threaded local heap
@@ -55,18 +56,21 @@ pub fn new() -> LocalHeap {
         }
     }
 
+    #[fixed_stack_segment] #[inline(never)]
     pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox {
         unsafe {
             return rust_boxed_region_malloc(self.boxed_region, td, size as size_t);
         }
     }
 
+    #[fixed_stack_segment] #[inline(never)]
     pub fn realloc(&mut self, ptr: *OpaqueBox, size: uint) -> *OpaqueBox {
         unsafe {
             return rust_boxed_region_realloc(self.boxed_region, ptr, size as size_t);
         }
     }
 
+    #[fixed_stack_segment] #[inline(never)]
     pub fn free(&mut self, box: *OpaqueBox) {
         unsafe {
             return rust_boxed_region_free(self.boxed_region, box);
@@ -75,6 +79,7 @@ pub fn free(&mut self, box: *OpaqueBox) {
 }
 
 impl Drop for LocalHeap {
+    #[fixed_stack_segment] #[inline(never)]
     fn drop(&self) {
         unsafe {
             rust_delete_boxed_region(self.boxed_region);
index 2ec43980419c93ee88f1214fefa301bb13158783..77303cb8c06cf5b04759624bd6ffa03d1ee29f5a 100644 (file)
@@ -24,6 +24,8 @@
 use tls = rt::thread_local_storage;
 
 /// Initialize the TLS key. Other ops will fail if this isn't executed first.
+#[fixed_stack_segment]
+#[inline(never)]
 pub fn init_tls_key() {
     unsafe {
         rust_initialize_rt_tls_key();
@@ -124,6 +126,8 @@ fn tls_key() -> tls::Key {
     }
 }
 
+#[fixed_stack_segment]
+#[inline(never)]
 fn maybe_tls_key() -> Option<tls::Key> {
     unsafe {
         let key: *mut c_void = rust_get_rt_tls_key();
@@ -149,8 +153,6 @@ fn maybe_tls_key() -> Option<tls::Key> {
     }
 
     extern {
-        #[fast_ffi]
         fn rust_get_rt_tls_key() -> *mut c_void;
     }
-
 }
index 4ee65a2b4495fa275d6baca8c4393229f4292155..f35304865bb3d7297442f78b899698f707d05122 100644 (file)
@@ -57,6 +57,7 @@ fn print(s: &str) {
 
 /// Configure logging by traversing the crate map and setting the
 /// per-module global logging flags based on the logging spec
+#[fixed_stack_segment] #[inline(never)]
 pub fn init(crate_map: *u8) {
     use c_str::ToCStr;
     use os;
@@ -78,8 +79,13 @@ pub fn init(crate_map: *u8) {
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn console_on() { unsafe { rust_log_console_on() } }
+
+#[fixed_stack_segment] #[inline(never)]
 pub fn console_off() { unsafe { rust_log_console_off() } }
+
+#[fixed_stack_segment] #[inline(never)]
 fn should_log_console() -> bool { unsafe { rust_should_log_console() != 0 } }
 
 extern {
index 58e86f97f71e16c4893c5e3cf5daee1c8c87b6d3..db1bfdf1bf56cb0cba485736f00bd5f6d74d9f03 100644 (file)
@@ -200,6 +200,18 @@ pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn())
     return exit_code;
 }
 
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+    (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+        extern {
+            fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+        }
+    )
+)
+}
+
 /// One-time runtime initialization.
 ///
 /// Initializes global state, including frobbing
@@ -215,9 +227,7 @@ pub fn init(argc: int, argv: **u8, crate_map: *u8) {
         rust_update_gc_metadata(crate_map);
     }
 
-    extern {
-        fn rust_update_gc_metadata(crate_map: *u8);
-    }
+    externfn!(fn rust_update_gc_metadata(crate_map: *u8));
 }
 
 /// One-time runtime cleanup.
index a126996892118074cafbb00753f8347cbf63177b..4b2a9b7a6cce40b418df65d081be82ac787a5ab9 100644 (file)
@@ -21,6 +21,8 @@ pub struct StackSegment {
 
 impl StackSegment {
     pub fn new(size: uint) -> StackSegment {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             // Crate a block of uninitialized values
             let mut stack = vec::with_capacity(size);
@@ -50,6 +52,8 @@ pub fn end(&self) -> *uint {
 
 impl Drop for StackSegment {
     fn drop(&self) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             // XXX: Using the FFI to call a C macro. Slow
             rust_valgrind_stack_deregister(self.valgrind_id);
index 01a8882e4f9a711974aa6131193d5c944c403784..22d2600507836159db13e1d5d8f7a1d11cd4b954 100644 (file)
@@ -441,6 +441,8 @@ pub fn try(&mut self, f: &fn()) {
     }
 
     pub fn begin_unwind(&mut self) -> ! {
+        #[fixed_stack_segment]; #[inline(never)];
+
         self.unwinding = true;
         unsafe {
             rust_begin_unwind(UNWIND_TOKEN);
index ca94468e1adaedbb670c421840a46fd9c2d6d108..a9331157749338123d784b36e8673ed77a012e41 100644 (file)
@@ -98,6 +98,8 @@ fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint,
     static RLIMIT_NOFILE: libc::c_int = 8;
 
     pub unsafe fn raise_fd_limit() {
+        #[fixed_stack_segment]; #[inline(never)];
+
         // The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
         // sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
         use ptr::{to_unsafe_ptr, to_mut_unsafe_ptr, mut_null};
@@ -305,6 +307,7 @@ pub fn cleanup_task(mut task: ~Task) {
 }
 
 /// Get a port number, starting at 9600, for use in tests
+#[fixed_stack_segment] #[inline(never)]
 pub fn next_test_port() -> u16 {
     unsafe {
         return rust_dbg_next_port(base_port() as libc::uintptr_t) as u16;
index 9f6cf68245eab59d8f521c720c1f715012626d10..61db08f4813ef5da516cd1d8ecc335cb43fc9a3d 100644 (file)
@@ -23,6 +23,8 @@ pub struct Thread {
 impl Thread {
     pub fn start(main: ~fn()) -> Thread {
         fn substart(main: &~fn()) -> *raw_thread {
+            #[fixed_stack_segment]; #[inline(never)];
+
             unsafe { rust_raw_thread_start(main) }
         }
         let raw = substart(&main);
@@ -34,6 +36,8 @@ fn substart(main: &~fn()) -> *raw_thread {
     }
 
     pub fn join(self) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         assert!(!self.joined);
         let mut this = self;
         unsafe { rust_raw_thread_join(this.raw_thread); }
@@ -43,6 +47,8 @@ pub fn join(self) {
 
 impl Drop for Thread {
     fn drop(&self) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         assert!(self.joined);
         unsafe { rust_raw_thread_delete(self.raw_thread) }
     }
index 5041b559ecbff8bb67b710f73012358920b19c08..a9cd29c18c9652d58a2fbe10704d236bf6650ccb 100644 (file)
 pub type Key = pthread_key_t;
 
 #[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
 pub unsafe fn create(key: &mut Key) {
     assert_eq!(0, pthread_key_create(key, null()));
 }
 
 #[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
 pub unsafe fn set(key: Key, value: *mut c_void) {
     assert_eq!(0, pthread_setspecific(key, value));
 }
 
 #[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
 pub unsafe fn get(key: Key) -> *mut c_void {
     pthread_getspecific(key)
 }
@@ -58,6 +64,8 @@ pub unsafe fn get(key: Key) -> *mut c_void {
 pub type Key = DWORD;
 
 #[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
 pub unsafe fn create(key: &mut Key) {
     static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
     *key = TlsAlloc();
@@ -65,11 +73,15 @@ pub unsafe fn create(key: &mut Key) {
 }
 
 #[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
 pub unsafe fn set(key: Key, value: *mut c_void) {
     assert!(0 != TlsSetValue(key, value))
 }
 
 #[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
 pub unsafe fn get(key: Key) -> *mut c_void {
     TlsGetValue(key)
 }
index 6280b64ecf51c71742a22751ef64ba176d0a0860..b8c7c8761e85d72cd2ffaae9a5320b5946e74fce 100644 (file)
@@ -17,6 +17,8 @@
 
 /// Get the number of cores available
 pub fn num_cpus() -> uint {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         return rust_get_num_cpus();
     }
@@ -94,11 +96,16 @@ pub fn abort(msg: &str) -> ! {
     rterrln!("%s", "");
     rterrln!("fatal runtime error: %s", msg);
 
-    unsafe { libc::abort(); }
+    abort();
+
+    fn abort() -> ! {
+        #[fixed_stack_segment]; #[inline(never)];
+        unsafe { libc::abort() }
+    }
 }
 
 pub fn set_exit_status(code: int) {
-
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         return rust_set_exit_status_newrt(code as libc::uintptr_t);
     }
@@ -109,7 +116,7 @@ pub fn set_exit_status(code: int) {
 }
 
 pub fn get_exit_status() -> int {
-
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         return rust_get_exit_status_newrt() as int;
     }
index 59833a16ed8b57a6faa1804fc0ae7239bfc0698c..9312efbf03e9ac4f0d9e3e66e7fc07bea31eca8d 100644 (file)
@@ -310,6 +310,8 @@ pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
 
 /// Transmute an owned vector to a Buf
 pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
+    #[fixed_stack_segment]; #[inline(never)];
+
     unsafe {
         let data = malloc(v.len() as size_t) as *u8;
         assert!(data.is_not_null());
@@ -323,6 +325,8 @@ pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
 
 /// Transmute a Buf that was once a ~[u8] back to ~[u8]
 pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> {
+    #[fixed_stack_segment]; #[inline(never)];
+
     if !(buf.len == 0 && buf.base.is_null()) {
         let v = unsafe { vec::from_buf(buf.base, buf.len as uint) };
         unsafe { free(buf.base as *c_void) };
index a26b8a3ad594de52f5bc128b24eaa580f664fe02..d4794da9b0f2884f47d00a1a48f7c66826b66a71 100644 (file)
@@ -45,6 +45,7 @@ enum SocketNameKind {
 
 fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
                                                  handle: U) -> Result<SocketAddr, IoError> {
+    #[fixed_stack_segment]; #[inline(never)];
 
     let getsockname = match sk {
         TcpPeer => uvll::rust_uv_tcp_getpeername,
@@ -406,6 +407,8 @@ fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> {
     }
 
     fn accept_simultaneously(&mut self) -> Result<(), IoError> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         let r = unsafe {
             uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 1 as c_int)
         };
@@ -417,6 +420,8 @@ fn accept_simultaneously(&mut self) -> Result<(), IoError> {
     }
 
     fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         let r = unsafe {
             uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 0 as c_int)
         };
@@ -524,6 +529,8 @@ fn peer_name(&mut self) -> Result<SocketAddr, IoError> {
     }
 
     fn control_congestion(&mut self) -> Result<(), IoError> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         let r = unsafe {
             uvll::rust_uv_tcp_nodelay(self.native_handle(), 0 as c_int)
         };
@@ -535,6 +542,8 @@ fn control_congestion(&mut self) -> Result<(), IoError> {
     }
 
     fn nodelay(&mut self) -> Result<(), IoError> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         let r = unsafe {
             uvll::rust_uv_tcp_nodelay(self.native_handle(), 1 as c_int)
         };
@@ -546,6 +555,8 @@ fn nodelay(&mut self) -> Result<(), IoError> {
     }
 
     fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         let r = unsafe {
             uvll::rust_uv_tcp_keepalive(self.native_handle(), 1 as c_int,
                                         delay_in_seconds as c_uint)
@@ -558,6 +569,8 @@ fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> {
     }
 
     fn letdie(&mut self) -> Result<(), IoError> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         let r = unsafe {
             uvll::rust_uv_tcp_keepalive(self.native_handle(), 0 as c_int, 0 as c_uint)
         };
index c04004dfbf6c788c26048798c2f85d9abefb4b67..65c0cffe5a073a57d607f0a1d93791b4233c0dd6 100644 (file)
@@ -124,6 +124,8 @@ pub enum uv_membership {
 }
 
 pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
     assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX);
     let size = rust_uv_handle_size(handle as uint);
     let p = malloc(size);
@@ -132,10 +134,14 @@ pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
 }
 
 pub unsafe fn free_handle(v: *c_void) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     free(v)
 }
 
 pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
     assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX);
     let size = rust_uv_req_size(req as uint);
     let p = malloc(size);
@@ -144,17 +150,22 @@ pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
 }
 
 pub unsafe fn free_req(v: *c_void) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     free(v)
 }
 
 #[test]
 fn handle_sanity_check() {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         assert_eq!(UV_HANDLE_TYPE_MAX as uint, rust_uv_handle_type_max());
     }
 }
 
 #[test]
+#[fixed_stack_segment]
+#[inline(never)]
 fn request_sanity_check() {
     unsafe {
         assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max());
@@ -162,59 +173,87 @@ fn request_sanity_check() {
 }
 
 pub unsafe fn loop_new() -> *c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_loop_new();
 }
 
 pub unsafe fn loop_delete(loop_handle: *c_void) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_loop_delete(loop_handle);
 }
 
 pub unsafe fn run(loop_handle: *c_void) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_run(loop_handle);
 }
 
 pub unsafe fn close<T>(handle: *T, cb: *u8) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_close(handle as *c_void, cb);
 }
 
 pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *c_void) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_walk(loop_handle, cb, arg);
 }
 
 pub unsafe fn idle_new() -> *uv_idle_t {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_idle_new()
 }
 
 pub unsafe fn idle_delete(handle: *uv_idle_t) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_idle_delete(handle)
 }
 
 pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_idle_init(loop_handle, handle)
 }
 
 pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_idle_start(handle, cb)
 }
 
 pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_idle_stop(handle)
 }
 
 pub unsafe fn udp_init(loop_handle: *uv_loop_t, handle: *uv_udp_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_init(loop_handle, handle);
 }
 
 pub unsafe fn udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_bind(server, addr, flags);
 }
 
 pub unsafe fn udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_bind6(server, addr, flags);
 }
 
 pub unsafe fn udp_send<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
                           addr: *sockaddr_in, cb: uv_udp_send_cb) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let buf_ptr = vec::raw::to_ptr(buf_in);
     let buf_cnt = buf_in.len() as i32;
     return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
@@ -222,6 +261,8 @@ pub unsafe fn udp_send<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
 
 pub unsafe fn udp_send6<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
                           addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let buf_ptr = vec::raw::to_ptr(buf_in);
     let buf_cnt = buf_in.len() as i32;
     return rust_uv_udp_send6(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
@@ -229,124 +270,184 @@ pub unsafe fn udp_send6<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
 
 pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb,
                              on_recv: uv_udp_recv_cb) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_recv_start(server, on_alloc, on_recv);
 }
 
 pub unsafe fn udp_recv_stop(server: *uv_udp_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_recv_stop(server);
 }
 
 pub unsafe fn get_udp_handle_from_send_req(send_req: *uv_udp_send_t) -> *uv_udp_t {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_get_udp_handle_from_send_req(send_req);
 }
 
 pub unsafe fn udp_get_sockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_getsockname(handle, name);
 }
 
 pub unsafe fn udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char,
                                  interface_addr: *c_char, membership: uv_membership) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_set_membership(handle, multicast_addr, interface_addr, membership as c_int);
 }
 
 pub unsafe fn udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_set_multicast_loop(handle, on);
 }
 
 pub unsafe fn udp_set_multicast_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_set_multicast_ttl(handle, ttl);
 }
 
 pub unsafe fn udp_set_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_set_ttl(handle, ttl);
 }
 
 pub unsafe fn udp_set_broadcast(handle: *uv_udp_t, on: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_udp_set_broadcast(handle, on);
 }
 
 pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_init(loop_handle, handle);
 }
 
 pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
                           addr_ptr: *sockaddr_in, after_connect_cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
 }
 
 pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
                            addr_ptr: *sockaddr_in6, after_connect_cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
 }
 
 pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr);
 }
 
 pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr);
 }
 
 pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_getpeername(tcp_handle_ptr, name);
 }
 
 pub unsafe fn tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_getsockname(handle, name);
 }
 
 pub unsafe fn tcp_nodelay(handle: *uv_tcp_t, enable: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_nodelay(handle, enable);
 }
 
 pub unsafe fn tcp_keepalive(handle: *uv_tcp_t, enable: c_int, delay: c_uint) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_keepalive(handle, enable, delay);
 }
 
 pub unsafe fn tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_tcp_simultaneous_accepts(handle, enable);
 }
 
 pub unsafe fn listen<T>(stream: *T, backlog: c_int, cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_listen(stream as *c_void, backlog, cb);
 }
 
 pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_accept(server as *c_void, client as *c_void);
 }
 
 pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let buf_ptr = vec::raw::to_ptr(buf_in);
     let buf_cnt = buf_in.len() as i32;
     return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
 }
 pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: uv_alloc_cb, on_read: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_read_start(stream as *c_void, on_alloc, on_read);
 }
 
 pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_read_stop(stream as *c_void);
 }
 
 pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_last_error(loop_handle);
 }
 
 pub unsafe fn strerror(err: *uv_err_t) -> *c_char {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_strerror(err);
 }
 pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_err_name(err);
 }
 
 pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_async_init(loop_handle, async_handle, cb);
 }
 
 pub unsafe fn async_send(async_handle: *uv_async_t) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_async_send(async_handle);
 }
 pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
+    #[fixed_stack_segment]; #[inline(never)];
+
     let out_buf = uv_buf_t { base: ptr::null(), len: 0 as size_t };
     let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf);
     rust_uv_buf_init(out_buf_ptr, input, len as size_t);
@@ -354,99 +455,149 @@ pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
 }
 
 pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_timer_init(loop_ptr, timer_ptr);
 }
 pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64,
                           repeat: u64) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_timer_start(timer_ptr, cb, timeout, repeat);
 }
 pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_timer_stop(timer_ptr);
 }
 
 pub unsafe fn is_ip4_addr(addr: *sockaddr) -> bool {
+    #[fixed_stack_segment]; #[inline(never)];
+
     match rust_uv_is_ipv4_sockaddr(addr) { 0 => false, _ => true }
 }
 
 pub unsafe fn is_ip6_addr(addr: *sockaddr) -> bool {
+    #[fixed_stack_segment]; #[inline(never)];
+
     match rust_uv_is_ipv6_sockaddr(addr) { 0 => false, _ => true }
 }
 
 pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in {
+    #[fixed_stack_segment]; #[inline(never)];
     do ip.with_c_str |ip_buf| {
         rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int)
     }
 }
 pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 {
+    #[fixed_stack_segment]; #[inline(never)];
     do ip.with_c_str |ip_buf| {
         rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int)
     }
 }
 
 pub unsafe fn malloc_sockaddr_storage() -> *sockaddr_storage {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_malloc_sockaddr_storage()
 }
 
 pub unsafe fn free_sockaddr_storage(ss: *sockaddr_storage) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_free_sockaddr_storage(ss);
 }
 
 pub unsafe fn free_ip4_addr(addr: *sockaddr_in) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_free_ip4_addr(addr);
 }
 
 pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_free_ip6_addr(addr);
 }
 
 pub unsafe fn ip4_name(addr: *sockaddr_in, dst: *u8, size: size_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_ip4_name(addr, dst, size);
 }
 
 pub unsafe fn ip6_name(addr: *sockaddr_in6, dst: *u8, size: size_t) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_ip6_name(addr, dst, size);
 }
 
 pub unsafe fn ip4_port(addr: *sockaddr_in) -> c_uint {
+    #[fixed_stack_segment]; #[inline(never)];
+
    return rust_uv_ip4_port(addr);
 }
 
 pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_ip6_port(addr);
 }
 
 // data access helpers
 pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_get_loop_for_uv_handle(handle as *c_void);
 }
 pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_get_stream_handle_from_connect_req(connect);
 }
 pub unsafe fn get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_get_stream_handle_from_write_req(write_req);
 }
 pub unsafe fn get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_get_data_for_uv_loop(loop_ptr)
 }
 pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_set_data_for_uv_loop(loop_ptr, data);
 }
 pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_get_data_for_uv_handle(handle as *c_void);
 }
 pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void);
 }
 pub unsafe fn get_data_for_req<T>(req: *T) -> *c_void {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_get_data_for_req(req as *c_void);
 }
 pub unsafe fn set_data_for_req<T, U>(req: *T, data: *U) {
+    #[fixed_stack_segment]; #[inline(never)];
+
     rust_uv_set_data_for_req(req as *c_void, data as *c_void);
 }
 pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_get_base_from_buf(buf);
 }
 pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
+    #[fixed_stack_segment]; #[inline(never)];
+
     return rust_uv_get_len_from_buf(buf);
 }
 pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
index a38254e89d2058114350d6047ccc7ad0a7c8b862..a43d448dae51f30a0bda7b6c7312c4df4ddd8d9a 100644 (file)
@@ -147,8 +147,11 @@ impl Process {
      * * options - Options to configure the environment of the process,
      *             the working directory and the standard IO streams.
      */
-    pub fn new(prog: &str, args: &[~str], options: ProcessOptions)
+    pub fn new(prog: &str, args: &[~str],
+               options: ProcessOptions)
                -> Process {
+        #[fixed_stack_segment]; #[inline(never)];
+
         let (in_pipe, in_fd) = match options.in_fd {
             None => {
                 let pipe = os::pipe();
@@ -287,6 +290,7 @@ pub fn error(&mut self) -> @io::Reader {
      * method does nothing.
      */
     pub fn close_input(&mut self) {
+        #[fixed_stack_segment]; #[inline(never)];
         match self.input {
             Some(-1) | None => (),
             Some(fd) => {
@@ -299,10 +303,12 @@ pub fn close_input(&mut self) {
     }
 
     fn close_outputs(&mut self) {
+        #[fixed_stack_segment]; #[inline(never)];
         fclose_and_null(&mut self.output);
         fclose_and_null(&mut self.error);
 
         fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
+            #[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
             match *f_opt {
                 Some(f) if !f.is_null() => {
                     unsafe {
@@ -387,6 +393,7 @@ fn destroy_internal(&mut self, force: bool) {
 
         #[cfg(windows)]
         fn killpid(pid: pid_t, _force: bool) {
+            #[fixed_stack_segment]; #[inline(never)];
             unsafe {
                 libc::funcs::extra::kernel32::TerminateProcess(
                     cast::transmute(pid), 1);
@@ -395,6 +402,8 @@ fn killpid(pid: pid_t, _force: bool) {
 
         #[cfg(unix)]
         fn killpid(pid: pid_t, force: bool) {
+            #[fixed_stack_segment]; #[inline(never)];
+
             let signal = if force {
                 libc::consts::os::posix88::SIGKILL
             } else {
@@ -447,6 +456,7 @@ fn spawn_process_os(prog: &str, args: &[~str],
                     env: Option<~[(~str, ~str)]>,
                     dir: Option<&Path>,
                     in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+    #[fixed_stack_segment]; #[inline(never)];
 
     use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
     use libc::consts::os::extra::{
@@ -630,6 +640,7 @@ fn spawn_process_os(prog: &str, args: &[~str],
                     env: Option<~[(~str, ~str)]>,
                     dir: Option<&Path>,
                     in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+    #[fixed_stack_segment]; #[inline(never)];
 
     use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
     use libc::funcs::bsd44::getdtablesize;
@@ -782,6 +793,7 @@ fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
 
 #[cfg(windows)]
 fn free_handle(handle: *()) {
+    #[fixed_stack_segment]; #[inline(never)];
     unsafe {
         libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
     }
@@ -848,6 +860,7 @@ fn waitpid(pid: pid_t) -> int {
 
     #[cfg(windows)]
     fn waitpid_os(pid: pid_t) -> int {
+        #[fixed_stack_segment]; #[inline(never)];
 
         use libc::types::os::arch::extra::DWORD;
         use libc::consts::os::extra::{
@@ -892,6 +905,7 @@ fn waitpid_os(pid: pid_t) -> int {
 
     #[cfg(unix)]
     fn waitpid_os(pid: pid_t) -> int {
+        #[fixed_stack_segment]; #[inline(never)];
 
         use libc::funcs::posix01::wait::*;
 
@@ -1069,6 +1083,8 @@ fn writeclose(fd: c_int, s: &str) {
     }
 
     fn readclose(fd: c_int) -> ~str {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             let file = os::fdopen(fd);
             let reader = io::FILE_reader(file, false);
@@ -1351,6 +1367,7 @@ fn test_add_to_env() {
     }
 
     fn running_on_valgrind() -> bool {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe { rust_running_on_valgrind() != 0 }
     }
 
index 9370e7b0e84c9021f7d03be5b04ad0c5485d591b..7f22f44a6f87286ec101244bcf5953aff531cac2 100644 (file)
@@ -220,3 +220,4 @@ mod std {
     pub use fmt;
     pub use to_bytes;
 }
+
index e4d63da3ee9262672dfbd54f2cdafda41e639176..2a8a79fcb32923f8e058ea8db25f2c43482da409 100644 (file)
@@ -2908,6 +2908,7 @@ fn test_contains_char() {
 
     #[test]
     fn test_map() {
+        #[fixed_stack_segment]; #[inline(never)];
         assert_eq!(~"", "".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
         assert_eq!(~"YMCA", "ymca".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
     }
index 3a11dee3138168fbb4a2c5303823d85746001601..8132bfe53778ba246c273019f2f674a94b6f51df 100644 (file)
@@ -147,7 +147,7 @@ pub unsafe fn local_pop<T: 'static>(handle: Handle,
                 // above.
                 let data = match util::replace(entry, None) {
                     Some((_, data, _)) => data,
-                    None => libc::abort(),
+                    None => abort(),
                 };
 
                 // Move `data` into transmute to get out the memory that it
@@ -252,7 +252,7 @@ unsafe fn local_get_with<T: 'static, U>(handle: Handle,
                         }
                     }
                 }
-                _ => libc::abort()
+                _ => abort()
             }
 
             // n.b. 'data' and 'loans' are both invalid pointers at the point
@@ -262,7 +262,7 @@ unsafe fn local_get_with<T: 'static, U>(handle: Handle,
             if return_loan {
                 match map[i] {
                     Some((_, _, ref mut loan)) => { *loan = NoLoan; }
-                    None => { libc::abort(); }
+                    None => { abort(); }
                 }
             }
             return ret;
@@ -270,6 +270,12 @@ unsafe fn local_get_with<T: 'static, U>(handle: Handle,
     }
 }
 
+fn abort() -> ! {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    unsafe { libc::abort() }
+}
+
 pub unsafe fn local_set<T: 'static>(handle: Handle,
                                     key: local_data::Key<T>,
                                     data: T) {
index 2c79f1c4ded985d71a6d5537117e4b5e21b0f9ae..0d2e62a77003e003e016033b5cb4bd2bae37d33c 100644 (file)
@@ -1045,15 +1045,12 @@ fn test_spawn_sched_childs_on_default_sched() {
 mod testrt {
     use libc;
 
-    #[nolink]
-    extern {
-        pub fn rust_dbg_lock_create() -> *libc::c_void;
-        pub fn rust_dbg_lock_destroy(lock: *libc::c_void);
-        pub fn rust_dbg_lock_lock(lock: *libc::c_void);
-        pub fn rust_dbg_lock_unlock(lock: *libc::c_void);
-        pub fn rust_dbg_lock_wait(lock: *libc::c_void);
-        pub fn rust_dbg_lock_signal(lock: *libc::c_void);
-    }
+    externfn!(fn rust_dbg_lock_create() -> *libc::c_void)
+    externfn!(fn rust_dbg_lock_destroy(lock: *libc::c_void))
+    externfn!(fn rust_dbg_lock_lock(lock: *libc::c_void))
+    externfn!(fn rust_dbg_lock_unlock(lock: *libc::c_void))
+    externfn!(fn rust_dbg_lock_wait(lock: *libc::c_void))
+    externfn!(fn rust_dbg_lock_signal(lock: *libc::c_void))
 }
 
 #[test]
index 005cedd0ffdfdccca83d869c3b519e091beb4f6e..6dbe68200b3b7fe23d28c62b72dc39083e7ec993 100644 (file)
@@ -145,16 +145,21 @@ mod dl {
     use result::*;
 
     pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
         do filename.with_c_str |raw_name| {
             dlopen(raw_name, Lazy as libc::c_int)
         }
     }
 
     pub unsafe fn open_internal() -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
+
         dlopen(ptr::null(), Lazy as libc::c_int)
     }
 
     pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+        #[fixed_stack_segment]; #[inline(never)];
+
         unsafe {
             do atomically {
                 let _old_error = dlerror();
@@ -172,9 +177,13 @@ pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
     }
 
     pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
+
         dlsym(handle, symbol)
     }
     pub unsafe fn close(handle: *libc::c_void) {
+        #[fixed_stack_segment]; #[inline(never)];
+
         dlclose(handle); ()
     }
 
@@ -204,18 +213,21 @@ mod dl {
     use result::*;
 
     pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
         do os::win32::as_utf16_p(filename.to_str()) |raw_name| {
             LoadLibraryW(raw_name)
         }
     }
 
     pub unsafe fn open_internal() -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
         let handle = ptr::null();
         GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void);
         handle
     }
 
     pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+        #[fixed_stack_segment]; #[inline(never)];
         unsafe {
             do atomically {
                 SetLastError(0);
@@ -232,9 +244,11 @@ pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
         }
     }
     pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+        #[fixed_stack_segment]; #[inline(never)];
         GetProcAddress(handle, symbol)
     }
     pub unsafe fn close(handle: *libc::c_void) {
+        #[fixed_stack_segment]; #[inline(never)];
         FreeLibrary(handle); ()
     }
 
index f721dd47a66a0f826027eb27fd3a7934c179d47e..6ad15bfc7c03939884be3590eaad06ffa789d946 100644 (file)
@@ -83,6 +83,8 @@ fn test_run_in_bare_thread_exchange() {
 /// can lead to deadlock. Calling change_dir_locked recursively will
 /// also deadlock.
 pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
+    #[fixed_stack_segment]; #[inline(never)];
+
     use os;
     use os::change_dir;
     use unstable::sync::atomically;
index c6b860eb1396654cd528a6892c06bbe96ced428b..29be094121c3b6350bc64c61e7b4e585747730f1 100644 (file)
@@ -322,7 +322,6 @@ pub fn new() -> LittleLock {
         }
     }
 
-    #[inline]
     pub unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
         do atomically {
             rust_lock_little_lock(self.l);
@@ -410,13 +409,28 @@ pub fn unwrap(self) -> T {
     }
 }
 
-extern {
-    fn rust_create_little_lock() -> rust_little_lock;
-    fn rust_destroy_little_lock(lock: rust_little_lock);
-    fn rust_lock_little_lock(lock: rust_little_lock);
-    fn rust_unlock_little_lock(lock: rust_little_lock);
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+    (fn $name:ident () $(-> $ret_ty:ty),*) => (
+        extern {
+            fn $name() $(-> $ret_ty),*;
+        }
+    );
+    (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+        extern {
+            fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+        }
+    )
+)
 }
 
+externfn!(fn rust_create_little_lock() -> rust_little_lock)
+externfn!(fn rust_destroy_little_lock(lock: rust_little_lock))
+externfn!(fn rust_lock_little_lock(lock: rust_little_lock))
+externfn!(fn rust_unlock_little_lock(lock: rust_little_lock))
+
 #[cfg(test)]
 mod tests {
     use cell::Cell;
index a4132e6c8793a5c550a7f3281c877ce49988a8f1..4bea1dc23e737a0d4ae660130ec9358030ddcb9b 100644 (file)
@@ -968,6 +968,85 @@ macro_rules! local_data_key (
             pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
         )
     )
+
+    // externfn! declares a wrapper for an external function.
+    // It is intended to be used like:
+    //
+    // externfn!(#[nolink]
+    //           #[abi = \"cdecl\"]
+    //           fn memcmp(cx: *u8, ct: *u8, n: u32) -> u32)
+    //
+    // Due to limitations in the macro parser, this pattern must be
+    // implemented with 4 distinct patterns (with attrs / without
+    // attrs CROSS with args / without ARGS).
+    //
+    // Also, this macro grammar allows for any number of return types
+    // because I couldn't figure out the syntax to specify at most one.
+    macro_rules! externfn(
+        (fn $name:ident () $(-> $ret_ty:ty),*) => (
+            pub unsafe fn $name() $(-> $ret_ty),* {
+                // Note: to avoid obscure bug in macros, keep these
+                // attributes *internal* to the fn
+                #[fixed_stack_segment];
+                #[inline(never)];
+                #[allow(missing_doc)];
+
+                return $name();
+
+                extern {
+                    fn $name() $(-> $ret_ty),*;
+                }
+            }
+        );
+        (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+            pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
+                // Note: to avoid obscure bug in macros, keep these
+                // attributes *internal* to the fn
+                #[fixed_stack_segment];
+                #[inline(never)];
+                #[allow(missing_doc)];
+
+                return $name($($arg_name),*);
+
+                extern {
+                    fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+                }
+            }
+        );
+        ($($attrs:attr)* fn $name:ident () $(-> $ret_ty:ty),*) => (
+            pub unsafe fn $name() $(-> $ret_ty),* {
+                // Note: to avoid obscure bug in macros, keep these
+                // attributes *internal* to the fn
+                #[fixed_stack_segment];
+                #[inline(never)];
+                #[allow(missing_doc)];
+
+                return $name();
+
+                $($attrs)*
+                extern {
+                    fn $name() $(-> $ret_ty),*;
+                }
+            }
+        );
+        ($($attrs:attr)* fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+            pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
+                // Note: to avoid obscure bug in macros, keep these
+                // attributes *internal* to the fn
+                #[fixed_stack_segment];
+                #[inline(never)];
+                #[allow(missing_doc)];
+
+                return $name($($arg_name),*);
+
+                $($attrs)*
+                extern {
+                    fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+                }
+            }
+        )
+    )
+
 }";
 }
 
index 4ec63d52251ec23b1dea5ffe9bc95c8bec2ed893..03cb96a3729af21dc9295d761534fde3f81f583c 100644 (file)
@@ -24,6 +24,7 @@ pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn fact(n: uint) -> uint {
     unsafe {
         info!("n = %?", n);
index 7c9fe73c974e2aa05db1a607d3d1c4a7a501908e..6f0c2f1de1ab45b1bb7f4cf7992a2e1e329d2cb3 100644 (file)
@@ -10,6 +10,7 @@
 
 // Exercise the unused_unsafe attribute in some positive and negative cases
 
+#[allow(cstack)];
 #[deny(unused_unsafe)];
 
 mod foo {
@@ -55,6 +56,7 @@ unsafe fn what() -> ~[~str] { fail!() }
         }
     }
 }
+
 unsafe fn good3() { foo::bar() }
 fn good4() { unsafe { foo::bar() } }
 
index 3f1bd83046241bd4c5d9fe298887e1cb5fed214e..1a2c22889fd82d680fc6a993f9077c7ee0f16f7c 100644 (file)
@@ -14,6 +14,7 @@
 
 use anonexternmod::*;
 
+#[fixed_stack_segment]
 pub fn main() {
     unsafe {
         rust_get_test_int();
index b305007d8d24844be061292c9682bc417d26092b..ed9caa1f65e2f52223ea868d95d5d7ac54a7ba3c 100644 (file)
@@ -16,6 +16,7 @@
     fn rust_get_test_int() -> libc::intptr_t;
 }
 
+#[fixed_stack_segment]
 pub fn main() {
     unsafe {
         let _ = rust_get_test_int();
index a0276e7e564fc133e68366672162e5ada0564d5a..f140c4621aa27319cec5be3f064514d951d4b2b1 100644 (file)
@@ -19,10 +19,12 @@ mod libc {
     }
 }
 
+#[fixed_stack_segment]
 fn atol(s: ~str) -> int {
     s.with_c_str(|x| unsafe { libc::atol(x) as int })
 }
 
+#[fixed_stack_segment]
 fn atoll(s: ~str) -> i64 {
     s.with_c_str(|x| unsafe { libc::atoll(x) as i64 })
 }
index de7aca88625d18407d8a9c3493e54678159d0065..27ad2fc46e07dab407a2c9e2b3b055917b7f696b 100644 (file)
@@ -27,6 +27,7 @@ pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
     }
 }
 
+#[fixed_stack_segment]
 fn count(n: uint) -> uint {
     unsafe {
         info!("n = %?", n);
index 518e48f29f7894dd0374109f17f325584201d3cb..6c90443636d3913cabe7008e469bdbf99697426f 100644 (file)
@@ -28,6 +28,7 @@ pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn count(n: uint) -> uint {
     unsafe {
         info!("n = %?", n);
index e1db41a32f1ef0eca3679f2aa953817442ab0b5d..5abd3c7b9d918ce55865b555aaa1c6ebe4cfa5de 100644 (file)
@@ -32,6 +32,7 @@ pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn count(n: uint) -> uint {
     unsafe {
         info!("n = %?", n);
index 66563a9a5fa671374ddddba2cf13321f216ff9fa..939487df174db1f1cf9059b746ab13179994b4d2 100644 (file)
@@ -27,6 +27,7 @@ pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn fact(n: uint) -> uint {
     unsafe {
         info!("n = %?", n);
index 97bbd3478a1a56ade7700dff7f882757ac81874f..7db7b898c0e6d7e29e1f059eeddc84c882e239c7 100644 (file)
@@ -13,6 +13,7 @@
 
 extern mod externcallback(vers = "0.1");
 
+#[fixed_stack_segment] #[inline(never)]
 fn fact(n: uint) -> uint {
     unsafe {
         info!("n = %?", n);
index 3389c56c83bf00afd777789a2f270c409f0a8721..147db0c0b2b0d9eb1c33ccf6b16b67c2ce3d6245 100644 (file)
@@ -20,6 +20,7 @@ struct TwoU32s {
     pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         let x = TwoU32s {one: 22, two: 23};
index 983817b12debcab6521053d851ba30cf982a4fc5..1937c366831ffc795de87530dcb49eefd1790b34 100644 (file)
@@ -19,6 +19,7 @@ struct TwoU64s {
     pub fn rust_dbg_extern_identity_TwoU64s(u: TwoU64s) -> TwoU64s;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         let x = TwoU64s {one: 22, two: 23};
index dd1110b59cdb0db7b02671b7cf0a55b60f27f8da..b543099b3b8f8f4990ecc508ef8d1ff20f9680d2 100644 (file)
@@ -24,6 +24,7 @@ struct TwoU64s {
     pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         let x = TwoU64s {one: 22, two: 23};
index 0cdfaf29a0582a44e9934eb12c26fa256ab508c8..f255746b75a8f683ca6ae60449866660904a0fcd 100644 (file)
@@ -14,6 +14,7 @@
     pub fn rust_dbg_extern_identity_u8(v: u8) -> u8;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         assert_eq!(22_u8, rust_dbg_extern_identity_u8(22_u8));
index cb0a061a7abd831e2d42e185b43e5c3bf1834e50..c80a0cd502fd351905a863140af3f5b765a2b702 100644 (file)
@@ -12,6 +12,7 @@
     pub fn rust_dbg_extern_identity_double(v: f64) -> f64;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64));
index aa54f014046127c735d695d8d74b1fec1177af95..c6fdabeab3dea0bbf4ee0f39903531bd6426966f 100644 (file)
@@ -14,6 +14,7 @@
     pub fn rust_dbg_extern_identity_u32(v: u32) -> u32;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         assert_eq!(22_u32, rust_dbg_extern_identity_u32(22_u32));
index 7c39080a5689732dc778d8554e015c0e12a31eee..09babc1109f8c3166bbd9058201c5b909fb8ec10 100644 (file)
@@ -14,6 +14,7 @@
     pub fn rust_dbg_extern_identity_u64(v: u64) -> u64;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         assert_eq!(22_u64, rust_dbg_extern_identity_u64(22_u64));
index ba671a1c4949f3bf82ea231708f881591fcbcd9b..2b9f99ca0105cb06a620c519252e4d0139275b33 100644 (file)
@@ -16,6 +16,7 @@ struct TwoU16s {
     pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         let y = rust_dbg_extern_return_TwoU16s();
index 90562f0f6b1cec5419f334d707acc5a6b9fdfbc7..f93a15bd80806c601aab3e1612346e939aff138c 100644 (file)
@@ -16,6 +16,7 @@ struct TwoU32s {
     pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         let y = rust_dbg_extern_return_TwoU32s();
index 9f878a90c142acdc923d0e8e44b6ff456ad71f2a..4dc31d715260b2707ffbd34521f941c198e31433 100644 (file)
@@ -16,6 +16,7 @@ struct TwoU64s {
     pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         let y = rust_dbg_extern_return_TwoU64s();
index 5d2fd14075844f46379e416535bd9445d590e38f..aae8b8a8587d0d7d91addae7f5b4fd24135d47f1 100644 (file)
@@ -16,6 +16,7 @@ struct TwoU8s {
     pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         let y = rust_dbg_extern_return_TwoU8s();
index 7719a25985082d5d7e78932ae33194087cb994ef..4eda3f34b6c15198a9f78d15d7b7efc22542a9b7 100644 (file)
@@ -32,6 +32,7 @@ pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn count(n: uint) -> uint {
     unsafe {
         rustrt::rust_dbg_call(cb, n)
index 2972b8559bbc1e62686f5d02fa1f773a1fc59d8b..ce51aafa9d80960160f663f1544535643ca5cb7f 100644 (file)
@@ -28,6 +28,7 @@ pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn count(n: uint) -> uint {
     unsafe {
         task::deschedule();
index 1d17959645acd91e5559d926af9145a29e68c982..c8acdbf44781c64bebe81228a742f753337d36ee 100644 (file)
@@ -2,9 +2,7 @@
 use std::libc;
 use std::unstable::run_in_bare_thread;
 
-extern {
-    pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t;
-}
+externfn!(fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t)
 
 pub fn main() {
     unsafe {
index 574ef59f0b642f3dfb7cc06792c9396c981a506e..3ff1ebb57322cfa10e67d32a56ce2cecbcda5e9a 100644 (file)
@@ -31,6 +31,7 @@ mod rustrt2 {
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         rustrt1::rust_get_test_int();
index 9ba332fb8221ef03191517ffeff53840fd25ceb3..57b59e4445e7718800ffe80de19a24fdda7b90a0 100644 (file)
@@ -21,6 +21,7 @@ mod libc {
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn strlen(str: ~str) -> uint {
     // C string is terminated with a zero
     do str.with_c_str |buf| {
index d914d52adf57da60012383a9b4dd182a4d0b0e1a..f9c2698eda499f882b5d6781718578db047c3f78 100644 (file)
@@ -18,6 +18,7 @@ mod rustrt {
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         rustrt::rust_get_test_int();
index 7e79311c5ad1f28da6f295538752b967e01634a1..1736428affb36cc0844152bba85fa5ff4d47b008 100644 (file)
@@ -17,6 +17,7 @@
 
 extern mod foreign_lib;
 
+#[fixed_stack_segment] #[inline(never)]
 pub fn main() {
     unsafe {
         let _foo = foreign_lib::rustrt::rust_get_test_int();
index 5ca7a589c6c49fbf823afe6ed4a3cee4adbae65a..1bb8a0008760b2ede0f90d6cdd9381ee03ce5259 100644 (file)
@@ -19,6 +19,7 @@ fn to_c_int(v: &mut int) -> &mut c_int {
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn lgamma(n: c_double, value: &mut int) -> c_double {
     unsafe {
         return m::lgamma(n, to_c_int(value));
index 6062f3075e2024c197dd2a79240c9871fd291049..b58c8738295da925923dba8c2c9c40ce5cacae97 100644 (file)
@@ -4,6 +4,7 @@
 pub struct Fd(c_int);
 
 impl Drop for Fd {
+    #[fixed_stack_segment] #[inline(never)]
     fn drop(&self) {
         unsafe {
             libc::close(**self);
index e0ac43f1f04fd0cd031947959aabf6791a6d1fc4..360ac75b3e75357381cc2aebc7fa15828f58b2af 100644 (file)
@@ -6,6 +6,7 @@ mod a {
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn main() {
     unsafe {
         a::free(transmute(0));
index 56000d7471d59ee06b179d7996d39a13e7f29723..201584d48a58571231daf8ee855752e2a033359e 100644 (file)
@@ -27,6 +27,7 @@ struct Ccx {
     x: int
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
     unsafe {
         cast::transmute(libc::malloc(sys::size_of::<Bcx<'blk>>()
@@ -38,6 +39,7 @@ fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> {
     return alloc(bcx.fcx.arena);
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn g(fcx : &Fcx) {
     let bcx = Bcx { fcx: fcx };
     let bcx2 = h(&bcx);
index 7af143a1529203406e27fa9faeb67f672e2e54b1..429b49375e0daa0576e3f8c1405dff560eed200b 100644 (file)
@@ -26,6 +26,7 @@ fn static_bound_set(a: &'static mut libc::c_int) {
     *a = 3;
 }
 
+#[fixed_stack_segment] #[inline(never)]
 unsafe fn run() {
     assert!(debug_static_mut == 3);
     debug_static_mut = 4;
index bf9d070c84ca68351377d5073ded89c677a8cbb2..1c39504ba717bc5cf5f7c9773983f049c753bcec 100644 (file)
@@ -21,6 +21,7 @@ mod rustrt {
     }
 }
 
+#[fixed_stack_segment] #[inline(never)]
 fn test1() {
     unsafe {
         let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa_u64,
@@ -40,6 +41,8 @@ fn test1() {
 }
 
 #[cfg(target_arch = "x86_64")]
+#[fixed_stack_segment]
+#[inline(never)]
 fn test2() {
     unsafe {
         let f = Floats { a: 1.234567890e-15_f64,
index 395aca5f8edb88a6275bff3468c4678cae0c00fc..3722dccf94b94001c38914056d6220fe9f082c47 100644 (file)
@@ -29,6 +29,7 @@ pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T)
 
 
 #[cfg(target_os = "win32")]
+#[fixed_stack_segment]
 pub fn main() {
     let heap = unsafe { kernel32::GetProcessHeap() };
     let mem = unsafe { kernel32::HeapAlloc(heap, 0u32, 100u32) };