]> git.lizzy.rs Git - rust.git/commitdiff
Use __morestack to detect stack overflow
authorAlex Crichton <alex@alexcrichton.com>
Thu, 17 Oct 2013 08:40:33 +0000 (01:40 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Sat, 19 Oct 2013 16:43:31 +0000 (09:43 -0700)
This commit resumes management of the stack boundaries and limits when switching
between tasks. This additionally leverages the __morestack function to run code
on "stack overflow". The current behavior is to abort the process, but this is
probably not the best behavior in the long term (for deails, see the comment I
wrote up in the stack exhaustion routine).

57 files changed:
mk/platform.mk
mk/rt.mk
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/foreign.rs
src/librustc/rustc.rs
src/libstd/rt/context.rs
src/libstd/rt/crate_map.rs
src/libstd/rt/env.rs
src/libstd/rt/sched.rs
src/libstd/rt/task.rs
src/libstd/rt/thread.rs
src/libstd/rt/thread_local_storage.rs
src/rt/arch/arm/ccall.S [deleted file]
src/rt/arch/arm/context.cpp [deleted file]
src/rt/arch/arm/context.h [deleted file]
src/rt/arch/arm/gpr.cpp [deleted file]
src/rt/arch/arm/gpr.h [deleted file]
src/rt/arch/arm/morestack.S
src/rt/arch/arm/record_sp.S
src/rt/arch/arm/regs.h [deleted file]
src/rt/arch/arm/sp.h [deleted file]
src/rt/arch/i386/ccall.S [deleted file]
src/rt/arch/i386/context.cpp [deleted file]
src/rt/arch/i386/context.h [deleted file]
src/rt/arch/i386/gpr.cpp [deleted file]
src/rt/arch/i386/gpr.h [deleted file]
src/rt/arch/i386/morestack.S
src/rt/arch/i386/regs.h [deleted file]
src/rt/arch/i386/sp.h [deleted file]
src/rt/arch/mips/ccall.S [deleted file]
src/rt/arch/mips/context.cpp [deleted file]
src/rt/arch/mips/context.h [deleted file]
src/rt/arch/mips/gpr.cpp [deleted file]
src/rt/arch/mips/gpr.h [deleted file]
src/rt/arch/mips/morestack.S
src/rt/arch/mips/record_sp.S
src/rt/arch/mips/regs.h [deleted file]
src/rt/arch/mips/sp.h [deleted file]
src/rt/arch/x86_64/_context.S
src/rt/arch/x86_64/ccall.S [deleted file]
src/rt/arch/x86_64/context.cpp [deleted file]
src/rt/arch/x86_64/context.h [deleted file]
src/rt/arch/x86_64/gpr.cpp [deleted file]
src/rt/arch/x86_64/gpr.h [deleted file]
src/rt/arch/x86_64/morestack.S
src/rt/arch/x86_64/regs.h
src/rt/arch/x86_64/sp.h [deleted file]
src/rt/rust_builtin.cpp
src/rt/rust_gpr_base.h [deleted file]
src/rt/rust_test_helpers.cpp
src/rt/rustrt.def.in
src/rt/sync/rust_thread.cpp
src/rt/sync/rust_thread.h
src/test/auxiliary/static_priv_by_default.rs
src/test/compile-fail/static-priv-by-default.rs
src/test/compile-fail/xcrate-private-by-default.rs
src/test/run-pass/no-std-xcrate.rs

index 8f9714e62d5b0ac77999be5c7fa0a5bf6757a747..7ba8f77ef980eb348a0faacafbf2c434823788e0 100644 (file)
@@ -507,7 +507,8 @@ define CFG_MAKE_TOOLCHAIN
 
   # For the ARM and MIPS crosses, use the toolchain assembler
   # XXX: We should be able to use the LLVM assembler
-  CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
+  CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
+                   $$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
 
   endif
 
index 347c32f17206eb2cb50c7a76d577dc6760074558..8a11d3553f45840d6127d5574a4709600da9f77d 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -91,8 +91,6 @@ RUNTIME_CXXS_$(1)_$(2) := \
               rt/miniz.cpp \
               rt/memory_region.cpp \
               rt/boxed_region.cpp \
-              rt/arch/$$(HOST_$(1))/context.cpp \
-              rt/arch/$$(HOST_$(1))/gpr.cpp \
               rt/rust_android_dummy.cpp \
               rt/rust_test_helpers.cpp
 
@@ -106,7 +104,6 @@ RUNTIME_CS_$(1)_$(2) := rt/sundown/src/autolink.c \
                        rt/sundown/html/html.c
 
 RUNTIME_S_$(1)_$(2) := rt/arch/$$(HOST_$(1))/_context.S \
-                       rt/arch/$$(HOST_$(1))/ccall.S \
                        rt/arch/$$(HOST_$(1))/record_sp.S
 
 RT_BUILD_DIR_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/stage$(2)
@@ -122,7 +119,7 @@ RUNTIME_OBJS_$(1)_$(2) := $$(RUNTIME_CXXS_$(1)_$(2):rt/%.cpp=$$(RT_BUILD_DIR_$(1
                      $$(RUNTIME_S_$(1)_$(2):rt/%.S=$$(RT_BUILD_DIR_$(1)_$(2))/%.o)
 ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1)_$(2))
 
-MORESTACK_OBJ_$(1)_$(2) := $$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/morestack.o
+MORESTACK_OBJS_$(1)_$(2) := $$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/morestack.o
 ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1)_$(2))
 
 $$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.cpp $$(MKFILE_DEPS)
@@ -140,9 +137,9 @@ $$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.S  $$(MKFILE_DEPS) \
        @$$(call E, compile: $$@)
        $$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<)
 
-$$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/libmorestack.a: $$(MORESTACK_OBJ_$(1)_$(2))
+$$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/libmorestack.a: $$(MORESTACK_OBJS_$(1)_$(2))
        @$$(call E, link: $$@)
-       $$(Q)$(AR_$(1)) rcs $$@ $$<
+       $$(Q)$(AR_$(1)) rcs $$@ $$^
 
 $$(RT_BUILD_DIR_$(1)_$(2))/$(CFG_RUNTIME_$(1)): $$(RUNTIME_OBJS_$(1)_$(2)) $$(MKFILE_DEPS) \
                         $$(RUNTIME_DEF_$(1)_$(2)) $$(LIBUV_LIB_$(1)) $$(JEMALLOC_LIB_$(1))
index e28d6a6899c8b96c635caf7075bd4c746fee2046..c6cc3092c11eccfb2d36db9c3e52e3ffcaa32d5d 100644 (file)
@@ -2226,6 +2226,7 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
                              [path_name(item.ident)]),
                 decl,
                 body,
+                item.attrs,
                 llfndecl,
                 item.id);
         } else if !generics.is_type_parameterized() {
index 9c83f7322045333d4327f9d82cb88c357973110d..09dd2f21a3b029b893b5124d38674a9cdb6bad10 100644 (file)
@@ -386,6 +386,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
                                       path: &ast_map::path,
                                       decl: &ast::fn_decl,
                                       body: &ast::Block,
+                                      attrs: &[ast::Attribute],
                                       llwrapfn: ValueRef,
                                       id: ast::NodeId) {
     let _icx = push_ctxt("foreign::build_foreign_fn");
@@ -393,7 +394,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
 
     unsafe { // unsafe because we call LLVM operations
         // Build up the Rust function (`foo0` above).
-        let llrustfn = build_rust_fn(ccx, path, decl, body, id);
+        let llrustfn = build_rust_fn(ccx, path, decl, body, attrs, id);
 
         // Build up the foreign wrapper (`foo` above).
         return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys);
@@ -403,6 +404,7 @@ fn build_rust_fn(ccx: @mut CrateContext,
                      path: &ast_map::path,
                      decl: &ast::fn_decl,
                      body: &ast::Block,
+                     attrs: &[ast::Attribute],
                      id: ast::NodeId)
                      -> ValueRef {
         let _icx = push_ctxt("foreign::foreign::build_rust_fn");
@@ -434,6 +436,7 @@ fn build_rust_fn(ccx: @mut CrateContext,
                t.repr(tcx));
 
         let llfndecl = base::decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, ps);
+        base::set_llvm_fn_attrs(attrs, llfndecl);
         base::trans_fn(ccx,
                        (*path).clone(),
                        decl,
index 1d9f37a2e877ea118079796a5b200ed6b9bbea56..712bf66bdaf26ba529d5ca9d4aeb00000dac1c43 100644 (file)
@@ -326,8 +326,12 @@ pub fn monitor(f: ~fn(@diagnostic::Emitter)) {
     use std::comm::*;
 
     // XXX: This is a hack for newsched since it doesn't support split stacks.
-    // rustc needs a lot of stack!
-    static STACK_SIZE: uint = 6000000;
+    // rustc needs a lot of stack! When optimizations are disabled, it needs
+    // even *more* stack than usual as well.
+    #[cfg(rtopt)]
+    static STACK_SIZE: uint = 6000000;  // 6MB
+    #[cfg(not(rtopt))]
+    static STACK_SIZE: uint = 20000000; // 20MB
 
     let (p, ch) = stream();
     let ch = SharedChan::new(ch);
index 853cc08a0ba773d3d511709f1b894b79b4be3c1f..f4616a8e18373ff6f6f1327c29231ed36b791019 100644 (file)
 use option::*;
 use super::stack::StackSegment;
 use libc::c_void;
+use uint;
 use cast::{transmute, transmute_mut_unsafe,
            transmute_region, transmute_mut_region};
 
+pub static RED_ZONE: uint = 20 * 1024;
+
 // FIXME #7761: Registers is boxed so that it is 16-byte aligned, for storing
 // SSE regs.  It would be marginally better not to do this. In C++ we
 // use an attribute on a struct.
@@ -24,14 +27,17 @@ pub struct Context {
     /// The context entry point, saved here for later destruction
     start: Option<~~fn()>,
     /// Hold the registers while the task or scheduler is suspended
-    regs: ~Registers
+    regs: ~Registers,
+    /// Lower bound and upper bound for the stack
+    stack_bounds: Option<(uint, uint)>,
 }
 
 impl Context {
     pub fn empty() -> Context {
         Context {
             start: None,
-            regs: new_regs()
+            regs: new_regs(),
+            stack_bounds: None,
         }
     }
 
@@ -47,7 +53,6 @@ pub fn new(start: ~fn(), stack: &mut StackSegment) -> Context {
 
         let fp: *c_void = task_start_wrapper as *c_void;
         let argp: *c_void = unsafe { transmute::<&~fn(), *c_void>(&*start) };
-        let stack_base: *uint = stack.start();
         let sp: *uint = stack.end();
         let sp: *mut uint = unsafe { transmute_mut_unsafe(sp) };
         // Save and then immediately load the current context,
@@ -57,11 +62,23 @@ pub fn new(start: ~fn(), stack: &mut StackSegment) -> Context {
             swap_registers(transmute_mut_region(&mut *regs), transmute_region(&*regs));
         };
 
-        initialize_call_frame(&mut *regs, fp, argp, sp, stack_base);
+        initialize_call_frame(&mut *regs, fp, argp, sp);
 
+        // Scheduler tasks don't have a stack in the "we allocated it" sense,
+        // but rather they run on pthreads stacks. We have complete control over
+        // them in terms of the code running on them (and hopefully they don't
+        // overflow). Additionally, their coroutine stacks are listed as being
+        // zero-length, so that's how we detect what's what here.
+        let stack_base: *uint = stack.start();
+        let bounds = if sp as uint == stack_base as uint {
+            None
+        } else {
+            Some((stack_base as uint, sp as uint))
+        };
         return Context {
             start: Some(start),
-            regs: regs
+            regs: regs,
+            stack_bounds: bounds,
         }
     }
 
@@ -79,8 +96,25 @@ pub fn swap(out_context: &mut Context, in_context: &Context) {
         let in_regs: &Registers = match in_context {
             &Context { regs: ~ref r, _ } => r
         };
-        rtdebug!("doing raw swap");
-        unsafe { swap_registers(out_regs, in_regs) };
+
+        rtdebug!("noting the stack limit and doing raw swap");
+
+        unsafe {
+            // Right before we switch to the new context, set the new context's
+            // stack limit in the OS-specified TLS slot. This also  means that
+            // we cannot call any more rust functions after record_stack_bounds
+            // returns because they would all likely fail due to the limit being
+            // invalid for the current task. Lucky for us `swap_registers` is a
+            // C function so we don't have to worry about that!
+            match in_context.stack_bounds {
+                Some((lo, hi)) => record_stack_bounds(lo, hi),
+                // If we're going back to one of the original contexts or
+                // something that's possibly not a "normal task", then reset
+                // the stack limit to 0 to make morestack never fail
+                None => record_stack_bounds(0, uint::max_value),
+            }
+            swap_registers(out_regs, in_regs)
+        }
     }
 }
 
@@ -89,6 +123,29 @@ pub fn swap(out_context: &mut Context, in_context: &Context) {
     fn swap_registers(out_regs: *mut Registers, in_regs: *Registers);
 }
 
+// Register contexts used in various architectures
+//
+// These structures all represent a context of one task throughout its
+// execution. Each struct is a representation of the architecture's register
+// set. When swapping between tasks, these register sets are used to save off
+// the current registers into one struct, and load them all from another.
+//
+// Note that this is only used for context switching, which means that some of
+// the registers may go unused. For example, for architectures with
+// callee/caller saved registers, the context will only reflect the callee-saved
+// registers. This is because the caller saved registers are already stored
+// elsewhere on the stack (if it was necessary anyway).
+//
+// Additionally, there may be fields on various architectures which are unused
+// entirely because they only reflect what is theoretically possible for a
+// "complete register set" to show, but user-space cannot alter these registers.
+// An example of this would be the segment selectors for x86.
+//
+// These structures/functions are roughly in-sync with the source files inside
+// of src/rt/arch/$arch. The only currently used function from those folders is
+// the `swap_registers` function, but that's only because for now segmented
+// stacks are disabled.
+
 #[cfg(target_arch = "x86")]
 struct Registers {
     eax: u32, ebx: u32, ecx: u32, edx: u32,
@@ -109,7 +166,7 @@ fn new_regs() -> ~Registers {
 
 #[cfg(target_arch = "x86")]
 fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
-                         sp: *mut uint, _stack_base: *uint) {
+                         sp: *mut uint) {
 
     let sp = align_down(sp);
     let sp = mut_offset(sp, -4);
@@ -125,6 +182,8 @@ fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
     regs.ebp = 0;
 }
 
+// windows requires saving more registers (both general and XMM), so the windows
+// register context must be larger.
 #[cfg(windows, target_arch = "x86_64")]
 type Registers = [uint, ..34];
 #[cfg(not(windows), target_arch = "x86_64")]
@@ -137,29 +196,14 @@ fn new_regs() -> ~Registers { ~([0, .. 22]) }
 
 #[cfg(target_arch = "x86_64")]
 fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
-                         sp: *mut uint, stack_base: *uint) {
+                         sp: *mut uint) {
 
-    // Redefinitions from regs.h
+    // Redefinitions from rt/arch/x86_64/regs.h
     static RUSTRT_ARG0: uint = 3;
     static RUSTRT_RSP: uint = 1;
     static RUSTRT_IP: uint = 8;
     static RUSTRT_RBP: uint = 2;
 
-    #[cfg(windows)]
-    fn initialize_tib(regs: &mut Registers, sp: *mut uint, stack_base: *uint) {
-        // Redefinitions from regs.h
-        static RUSTRT_ST1: uint = 11; // stack bottom
-        static RUSTRT_ST2: uint = 12; // stack top
-        regs[RUSTRT_ST1] = sp as uint;
-        regs[RUSTRT_ST2] = stack_base as uint;
-    }
-    #[cfg(not(windows))]
-    fn initialize_tib(_: &mut Registers, _: *mut uint, _: *uint) {
-    }
-
-    // Win64 manages stack range at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
-    initialize_tib(regs, sp, stack_base);
-
     let sp = align_down(sp);
     let sp = mut_offset(sp, -1);
 
@@ -167,9 +211,9 @@ fn initialize_tib(_: &mut Registers, _: *mut uint, _: *uint) {
     unsafe { *sp = 0; }
 
     rtdebug!("creating call frame");
-    rtdebug!("fptr {}", fptr as uint);
-    rtdebug!("arg {}", arg as uint);
-    rtdebug!("sp {}", sp as uint);
+    rtdebug!("fptr {}", fptr);
+    rtdebug!("arg {}", arg);
+    rtdebug!("sp {}", sp);
 
     regs[RUSTRT_ARG0] = arg as uint;
     regs[RUSTRT_RSP] = sp as uint;
@@ -187,7 +231,7 @@ fn new_regs() -> ~Registers { ~([0, .. 32]) }
 
 #[cfg(target_arch = "arm")]
 fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
-                         sp: *mut uint, _stack_base: *uint) {
+                         sp: *mut uint) {
     let sp = align_down(sp);
     // sp of arm eabi is 8-byte aligned
     let sp = mut_offset(sp, -2);
@@ -208,7 +252,7 @@ fn new_regs() -> ~Registers { ~([0, .. 32]) }
 
 #[cfg(target_arch = "mips")]
 fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
-                         sp: *mut uint, _stack_base: *uint) {
+                         sp: *mut uint) {
     let sp = align_down(sp);
     // sp of mips o32 is 8-byte aligned
     let sp = mut_offset(sp, -2);
@@ -236,3 +280,182 @@ pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
     use std::sys::size_of;
     (ptr as int + count * (size_of::<T>() as int)) as *mut T
 }
+
+#[inline(always)]
+pub unsafe fn record_stack_bounds(stack_lo: uint, stack_hi: uint) {
+    // When the old runtime had segmented stacks, it used a calculation that was
+    // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic
+    // symbol resolution, llvm function calls, etc. In theory this red zone
+    // value is 0, but it matters far less when we have gigantic stacks because
+    // we don't need to be so exact about our stack budget. The "fudge factor"
+    // was because LLVM doesn't emit a stack check for functions < 256 bytes in
+    // size. Again though, we have giant stacks, so we round all these
+    // calculations up to the nice round number of 20k.
+    record_sp_limit(stack_lo + RED_ZONE);
+
+    return target_record_stack_bounds(stack_lo, stack_hi);
+
+    #[cfg(not(windows))] #[cfg(not(target_arch = "x86_64"))] #[inline(always)]
+    unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {}
+    #[cfg(windows, target_arch = "x86_64")] #[inline(always)]
+    unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) {
+        // Windows compiles C functions which may check the stack bounds. This
+        // means that if we want to perform valid FFI on windows, then we need
+        // to ensure that the stack bounds are what they truly are for this
+        // task. More info can be found at:
+        //   https://github.com/mozilla/rust/issues/3445#issuecomment-26114839
+        //
+        // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
+        asm!("mov $0, %gs:0x08" :: "r"(stack_lo) :: "volatile");
+        asm!("mov $0, %gs:0x10" :: "r"(stack_hi) :: "volatile");
+    }
+}
+
+/// Records the current limit of the stack as specified by `end`.
+///
+/// This is stored in an OS-dependent location, likely inside of the thread
+/// local storage. The location that the limit is stored is a pre-ordained
+/// location because it's where LLVM has emitted code to check.
+///
+/// Note that this cannot be called under normal circumstances. This function is
+/// changing the stack limit, so upon returning any further function calls will
+/// possibly be triggering the morestack logic if you're not careful.
+///
+/// Also note that this and all of the inside functions are all flagged as
+/// "inline(always)" because they're messing around with the stack limits.  This
+/// would be unfortunate for the functions themselves to trigger a morestack
+/// invocation (if they were an actual function call).
+#[inline(always)]
+pub unsafe fn record_sp_limit(limit: uint) {
+    return target_record_sp_limit(limit);
+
+    // x86-64
+    #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $$0x60+90*8, %rsi
+              movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile")
+    }
+    #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile")
+    }
+    #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block
+        // store this inside of the "arbitrary data slot", but double the size
+        // because this is 64 bit instead of 32 bit
+        asm!("movq $0, %gs:0x28" :: "r"(limit) :: "volatile")
+    }
+    #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $0, %fs:24" :: "r"(limit) :: "volatile")
+    }
+
+    // x86
+    #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movl $$0x48+90*4, %eax
+              movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile")
+    }
+    #[cfg(target_arch = "x86", target_os = "linux")]
+    #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile")
+    }
+    #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block
+        // store this inside of the "arbitrary data slot"
+        asm!("movl $0, %fs:0x14" :: "r"(limit) :: "volatile")
+    }
+
+    // mips, arm - Some brave soul can port these to inline asm, but it's over
+    //             my head personally
+    #[cfg(target_arch = "mips")]
+    #[cfg(target_arch = "arm")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        return record_sp_limit(limit as *c_void);
+        extern {
+            #[rust_stack]
+            fn record_sp_limit(limit: *c_void);
+        }
+    }
+}
+
+/// The counterpart of the function above, this function will fetch the current
+/// stack limit stored in TLS.
+///
+/// Note that all of these functions are meant to be exact counterparts of their
+/// brethren above, except that the operands are reversed.
+///
+/// As with the setter, this function does not have a __morestack header and can
+/// therefore be called in a "we're out of stack" situation.
+#[inline(always)]
+// NOTE: after the next snapshot, can remove the initialization before inline
+//       assembly due to an improvement in how it's handled, then this specific
+//       allow directive should get removed.
+#[allow(dead_assignment)]
+pub unsafe fn get_sp_limit() -> uint {
+    return target_get_sp_limit();
+
+    // x86-64
+    #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let mut limit: uint = 0;
+        asm!("movq $$0x60+90*8, %rsi
+              movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let mut limit: uint = 0;
+        asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let mut limit: uint = 0;
+        asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let mut limit: uint = 0;
+        asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+
+    // x86
+    #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let mut limit: uint = 0;
+        asm!("movl $$0x48+90*4, %eax
+              movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86", target_os = "linux")]
+    #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let mut limit: uint = 0;
+        asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let mut limit: uint = 0;
+        asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+
+    // mips, arm - Some brave soul can port these to inline asm, but it's over
+    //             my head personally
+    #[cfg(target_arch = "mips")]
+    #[cfg(target_arch = "arm")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        return get_sp_limit() as uint;
+        extern {
+            #[rust_stack]
+            fn get_sp_limit() -> *c_void;
+        }
+    }
+}
index 8785dcca7bdbf5bf57b5ed01793d42bb8856e380..96a0069e851568a7b27f16dfeb8d505ad7a9c5ea 100644 (file)
@@ -17,7 +17,7 @@
 // and instead look them up at runtime, which we need to resolve
 // the crate_map properly.
 #[cfg(target_os = "macos")]
-#[link_args = "-undefined dynamic_lookup"]
+#[link_args = "-Wl,-U,__rust_crate_map_toplevel"]
 extern {}
 
 pub struct ModEntry<'self> {
index 5b8406551204270782e291798d0436af7e4ebc9d..c02e7fe90131f8ada68cfca017d5ca6541aa70e4 100644 (file)
@@ -17,7 +17,7 @@
 // Note that these are all accessed without any synchronization.
 // They are expected to be initialized once then left alone.
 
-static mut MIN_STACK: uint = 2000000;
+static mut MIN_STACK: uint = 4000000;
 static mut DEBUG_BORROW: bool = false;
 
 pub fn init() {
index 0a4622bc65eefefa65621ab3d28a5cb2ad385e6a..c636a16903700b43610fd6cbb7165c1080385e73 100644 (file)
@@ -173,7 +173,7 @@ pub fn bootstrap(~self, task: ~Task) {
 
         // Now that we have an empty task struct for the scheduler
         // task, put it in TLS.
-        Local::put::(sched_task);
+        Local::put(sched_task);
 
         // Before starting our first task, make sure the idle callback
         // is active. As we do not start in the sleep state this is
index d5278975d8dfee89295937378959b4fdb5702b12..1b1e4e7d426ac3c40fcf452e99b1577498d67486 100644 (file)
@@ -29,6 +29,7 @@
 use super::local_heap::LocalHeap;
 use rt::sched::{Scheduler, SchedHandle};
 use rt::stack::{StackSegment, StackPool};
+use rt::context;
 use rt::context::Context;
 use unstable::finally::Finally;
 use task::spawn::Taskgroup;
@@ -465,6 +466,80 @@ pub fn begin_unwind(&mut self) -> ! {
     }
 }
 
+/// This function is invoked from rust's current __morestack function. Segmented
+/// stacks are currently not enabled as segmented stacks, but rather one giant
+/// stack segment. This means that whenever we run out of stack, we want to
+/// truly consider it to be stack overflow rather than allocating a new stack.
+#[no_mangle]      // - this is called from C code
+#[no_split_stack] // - it would be sad for this function to trigger __morestack
+#[doc(hidden)] // XXX: this function shouldn't have to be `pub` to get exported
+               //      so it can be linked against, we should have a better way
+               //      of specifying that.
+pub extern "C" fn rust_stack_exhausted() {
+    use rt::in_green_task_context;
+    use rt::task::Task;
+    use rt::local::Local;
+    use rt::logging::Logger;
+    use unstable::intrinsics;
+
+    unsafe {
+        // We're calling this function because the stack just ran out. We need
+        // to call some other rust functions, but if we invoke the functions
+        // right now it'll just trigger this handler being called again. In
+        // order to alleviate this, we move the stack limit to be inside of the
+        // red zone that was allocated for exactly this reason.
+        let limit = context::get_sp_limit();
+        context::record_sp_limit(limit - context::RED_ZONE / 2);
+
+        // This probably isn't the best course of action. Ideally one would want
+        // to unwind the stack here instead of just aborting the entire process.
+        // This is a tricky problem, however. There's a few things which need to
+        // be considered:
+        //
+        //  1. We're here because of a stack overflow, yet unwinding will run
+        //     destructors and hence arbitrary code. What if that code overflows
+        //     the stack? One possibility is to use the above allocation of an
+        //     extra 10k to hope that we don't hit the limit, and if we do then
+        //     abort the whole program. Not the best, but kind of hard to deal
+        //     with unless we want to switch stacks.
+        //
+        //  2. LLVM will optimize functions based on whether they can unwind or
+        //     not. It will flag functions with 'nounwind' if it believes that
+        //     the function cannot trigger unwinding, but if we do unwind on
+        //     stack overflow then it means that we could unwind in any function
+        //     anywhere. We would have to make sure that LLVM only places the
+        //     nounwind flag on functions which don't call any other functions.
+        //
+        //  3. The function that overflowed may have owned arguments. These
+        //     arguments need to have their destructors run, but we haven't even
+        //     begun executing the function yet, so unwinding will not run the
+        //     any landing pads for these functions. If this is ignored, then
+        //     the arguments will just be leaked.
+        //
+        // Exactly what to do here is a very delicate topic, and is possibly
+        // still up in the air for what exactly to do. Some relevant issues:
+        //
+        //  #3555 - out-of-stack failure leaks arguments
+        //  #3695 - should there be a stack limit?
+        //  #9855 - possible strategies which could be taken
+        //  #9854 - unwinding on windows through __morestack has never worked
+        //  #2361 - possible implementation of not using landing pads
+
+        if in_green_task_context() {
+            do Local::borrow |task: &mut Task| {
+                let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or("<unnamed>");
+
+                format_args!(|args| { task.logger.log(args) },
+                             "task '{}' has overflowed its stack", n);
+            }
+        } else {
+            rterrln!("stack overflow in non-task context");
+        }
+
+        intrinsics::abort();
+    }
+}
+
 /// This is the entry point of unwinding for things like lang items and such.
 /// The arguments are normally generated by the compiler.
 pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! {
@@ -481,22 +556,33 @@ pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! {
         let msg = match msg.as_str() {
             Some(s) => s, None => rtabort!("message wasn't utf8?")
         };
-        let file = match file.as_str() {
-            Some(s) => s, None => rtabort!("message wasn't utf8?")
-        };
 
         if in_green_task_context() {
             // Be careful not to allocate in this block, if we're failing we may
             // have been failing due to a lack of memory in the first place...
             do Local::borrow |task: &mut Task| {
                 let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or("<unnamed>");
-                format_args!(|args| { task.logger.log(args) },
-                             "task '{}' failed at '{}', {}:{}",
-                             n, msg, file, line);
+
+                match file.as_str() {
+                    Some(file) => {
+                        format_args!(|args| { task.logger.log(args) },
+                                     "task '{}' failed at '{}', {}:{}",
+                                     n, msg, file, line);
+                    }
+                    None => {
+                        format_args!(|args| { task.logger.log(args) },
+                                     "task '{}' failed at '{}'", n, msg);
+                    }
+                }
             }
         } else {
-            rterrln!("failed in non-task context at '{}', {}:{}",
-                     msg, file, line as int);
+            match file.as_str() {
+                Some(file) => {
+                    rterrln!("failed in non-task context at '{}', {}:{}",
+                             msg, file, line as int);
+                }
+                None => rterrln!("failed in non-task context at '{}'", msg),
+            }
         }
 
         let task: *mut Task = Local::unsafe_borrow();
index 8b64fda21364a2ca9a40fef1b22bb1bbf858399a..e774b81da3501d3e29b1dd3578b04be7fba65d53 100644 (file)
@@ -8,8 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use cast;
 use libc;
 use ops::Drop;
+use unstable::raw;
+use uint;
 
 #[allow(non_camel_case_types)] // runtime type
 type raw_thread = libc::c_void;
 pub struct Thread {
     main: ~fn(),
     raw_thread: *raw_thread,
-    joined: bool
+    joined: bool,
 }
 
 impl Thread {
+    #[fixed_stack_segment] #[inline(never)]
     pub fn start(main: ~fn()) -> Thread {
-        fn substart(main: &~fn()) -> *raw_thread {
-            #[fixed_stack_segment]; #[inline(never)];
-
-            unsafe { rust_raw_thread_start(main) }
+        // This is the starting point of rust os threads. The first thing we do
+        // is make sure that we don't trigger __morestack (also why this has a
+        // no_split_stack annotation), and then we re-build the main function
+        // and invoke it from there.
+        #[no_split_stack]
+        extern "C" fn thread_start(code: *(), env: *()) {
+            use rt::context;
+            unsafe {
+                context::record_stack_bounds(0, uint::max_value);
+                let f: &fn() = cast::transmute(raw::Closure {
+                    code: code,
+                    env: env,
+                });
+                f();
+            }
         }
-        let raw = substart(&main);
+
+        let raw_thread = unsafe {
+            let c: raw::Closure = cast::transmute_copy(&main);
+            let raw::Closure { code, env } = c;
+            rust_raw_thread_start(thread_start, code, env)
+        };
         Thread {
             main: main,
-            raw_thread: raw,
-            joined: false
+            raw_thread: raw_thread,
+            joined: false,
         }
     }
 
@@ -55,7 +75,8 @@ fn drop(&mut self) {
 }
 
 extern {
-    pub fn rust_raw_thread_start(f: &(~fn())) -> *raw_thread;
-    pub fn rust_raw_thread_join(thread: *raw_thread);
-    pub fn rust_raw_thread_delete(thread: *raw_thread);
+    fn rust_raw_thread_start(f: extern "C" fn(*(), *()),
+                             code: *(), env: *()) -> *raw_thread;
+    fn rust_raw_thread_join(thread: *raw_thread);
+    fn rust_raw_thread_delete(thread: *raw_thread);
 }
index cd89d09ffc0ab0d584c7bb56f626d5bb33a4b828..ddb104240f2c615ce2e5112d2f4c4a645891cc58 100644 (file)
@@ -27,15 +27,11 @@ pub unsafe fn create(key: &mut Key) {
 }
 
 #[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)
 }
@@ -53,8 +49,21 @@ pub unsafe fn get(key: Key) -> *mut c_void {
 #[cfg(unix)]
 extern {
     fn pthread_key_create(key: *mut pthread_key_t, dtor: *u8) -> c_int;
-    fn pthread_setspecific(key: pthread_key_t, value: *mut c_void) -> c_int;
+
+    // This function is a very cheap operation on both osx and unix. On osx, it
+    // turns out it's just three instructions, and on unix it's a cheap function
+    // which only uses a very small amount of stack.
+    //
+    // This is not marked as such because we think it has a small stack, but
+    // rather we would like to be able to fetch information from
+    // thread-local-storage when a task is running very low on its stack budget.
+    // For example, this is invoked whenever stack overflow is detected, and we
+    // obviously have very little budget to deal with (certainly not anything
+    // close to a fixed_stack_segment)
+    #[rust_stack]
     fn pthread_getspecific(key: pthread_key_t) -> *mut c_void;
+    #[rust_stack]
+    fn pthread_setspecific(key: pthread_key_t, value: *mut c_void) -> c_int;
 }
 
 #[cfg(windows)]
@@ -70,31 +79,37 @@ 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)
 }
 
 #[cfg(windows, target_arch = "x86")]
 extern "stdcall" {
-       fn TlsAlloc() -> DWORD;
-       fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
-       fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
+    fn TlsAlloc() -> DWORD;
+
+    // See the reasoning in pthread_getspecific as to why this has the
+    // 'rust_stack' attribute, as this function was also verified to only
+    // require a small amount of stack.
+    #[rust_stack]
+    fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
+    #[rust_stack]
+    fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
 }
 
 #[cfg(windows, target_arch = "x86_64")]
 extern {
-       fn TlsAlloc() -> DWORD;
-       fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
-       fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
+    fn TlsAlloc() -> DWORD;
+
+    // See above.
+    #[rust_stack]
+    fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
+    #[rust_stack]
+    fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
 }
 
 #[test]
diff --git a/src/rt/arch/arm/ccall.S b/src/rt/arch/arm/ccall.S
deleted file mode 100644 (file)
index 3350a04..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Mark stack as non-executable
-#if defined(__linux__) && defined(__ELF__)
-.section       .note.GNU-stack, "", %progbits
-#endif
-
-.text
-.code 32
-.arm
-.align
-
-.globl __morestack
-.hidden __morestack
-.type __morestack, %function
-__morestack:
-       .fnstart
-       .save {r4, fp, lr}
-       push {r4, fp, lr}
-    .movsp r4
-       mov r4, sp
-       mov sp, r2
-       mov fp, sp
-       blx r1
-       mov sp, r4
-       pop {r4, fp, lr}
-       mov pc, lr
-       .fnend
diff --git a/src/rt/arch/arm/context.cpp b/src/rt/arch/arm/context.cpp
deleted file mode 100644 (file)
index 7d90668..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// xfail-license
-
-#include "context.h"
-#include "../../rust_globals.h"
-
-extern "C" void CDECL swap_registers(registers_t *oregs,
-                                     registers_t *regs)
-asm ("swap_registers");
-
-context::context()
-{
-    assert((void*)&regs == (void*)this);
-    memset(&regs, 0, sizeof(regs));
-}
-
-void context::swap(context &out)
-{
-    swap_registers(&out.regs, &regs);
-}
-
-void context::call(void *f, void *arg, void *stack)
-{
-  // Get the current context, which we will then modify to call the
-  // given function.
-  swap(*this);
-
-  // set up the stack
-  uint32_t *sp = ( uint32_t *)stack;
-  sp = align_down(sp);
-  // The final return address. 0 indicates the bottom of the stack
-  // sp of arm eabi is 8-byte aligned
-  sp -= 2;
-  *sp = 0;
-
-  regs.data[0] = ( uint32_t )arg; // r0
-  regs.data[13] = ( uint32_t )sp; //#52 sp, r13
-  regs.data[14] = ( uint32_t )f;  //#60 pc, r15 --> lr,
-  // Last base pointer on the stack should be 0
-}
diff --git a/src/rt/arch/arm/context.h b/src/rt/arch/arm/context.h
deleted file mode 100644 (file)
index 54f0df7..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// -*- mode: c++ -*-
-// xfail-license
-
-#ifndef CONTEXT_H
-#define CONTEXT_H
-
-#include <cstdlib>
-#include <inttypes.h>
-#include <stdint.h>
-//#include <xmmintrin.h>
-
-#include "vg/memcheck.h"
-
-template<typename T>
-T align_down(T sp)
-{
-    // There is no platform we care about that needs more than a
-    // 16-byte alignment.
-    return (T)((uint32_t)sp & ~(16 - 1));
-}
-
-// The struct in which we store the saved data.  This is mostly the
-// volatile registers and instruction pointer, but it also includes
-// RCX/RDI which are used to pass arguments.  The indices for each
-// register are found in "regs.h".  Note that the alignment must be
-// 16 bytes so that SSE instructions can be used.
-#include "regs.h"
-struct registers_t {
-    uint32_t data[RUSTRT_MAX];
-} __attribute__((aligned(16)));
-
-class context {
-public:
-    registers_t regs;
-
-    context();
-
-    context *next;
-
-    void swap(context &out);
-    void call(void *f, void *arg, void *sp);
-};
-
-#endif
diff --git a/src/rt/arch/arm/gpr.cpp b/src/rt/arch/arm/gpr.cpp
deleted file mode 100644 (file)
index 77ec9d5..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// xfail-license
-
-#include "gpr.h"
-
-#define LOAD(rn) do { \
-    uintptr_t tmp; \
-    asm("mov %%" #rn ",%0" : "=r" (tmp) :); \
-    this->rn = tmp; \
-} while (0)
-
-void rust_gpr::load() {
-    LOAD(r0); LOAD(r1); LOAD(r2); LOAD(r3);
-    LOAD(r4); LOAD(r5); LOAD(r6); LOAD(r7);
-    LOAD(r8);  LOAD(r9);  LOAD(r10); LOAD(r11);
-    LOAD(r12); LOAD(r13); LOAD(r14); LOAD(r15);
-}
diff --git a/src/rt/arch/arm/gpr.h b/src/rt/arch/arm/gpr.h
deleted file mode 100644 (file)
index c8a3e91..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// xfail-license
-// General-purpose registers. This structure is used during stack crawling.
-
-#ifndef GPR_H
-#define GPR_H
-
-#include "rust_gpr_base.h"
-
-class rust_gpr : public rust_gpr_base {
-public:
-    uintptr_t r0, r1, r2, r3, r4, r5, r6, r7;
-    uintptr_t  r8,  r9, r10, r11, r12, r13, r14, r15;
-
-    inline uintptr_t get_fp() { return r11; }
-    inline uintptr_t get_ip() { return r12; }
-
-    inline void set_fp(uintptr_t new_fp) { r11 = new_fp; }
-    inline void set_ip(uintptr_t new_ip) { r12 = new_ip; }
-
-    void load();
-};
-
-#endif
index f0ec3f4b7a5118e6c6863654eddce2c61ea2d94f..219f0962d771c000edd75e7f90604b171b55af39 100644 (file)
@@ -3,13 +3,14 @@
 .section       .note.GNU-stack, "", %progbits
 #endif
 
+/* See i386/morestack.S for the lengthy, general explanation. */
+
 .text
 .code 32
 .arm
 .align
 
-.global upcall_new_stack
-.global upcall_del_stack
+.global rust_stack_exhausted
 .global __morestack
 .hidden __morestack
 
@@ -32,40 +33,8 @@ __morestack:
     // Save argument registers of the original function
     push {r0, r1, r2, r3, lr}
 
-    mov r0, r4         // The amount of stack needed
-    add r1, fp, #20    // Address of stack arguments
-    mov r2, r5         // Size of stack arguments
-
     // Create new stack
-    bl upcall_new_stack@plt
-
-    // Hold new stack pointer
-    mov r5, r0
-
-    // Pop the saved arguments
-    pop {r0, r1, r2, r3, lr}
-
-    // Grab the return pointer
-    add r4, lr, #16    // Skip past the return
-    mov sp, r5         // Swich to the new stack
-    mov lr, pc
-    mov pc, r4         // Call the original function
-
-    // Switch back to rust stack
-    mov sp, r6
-
-    // Save return value
-       mov r4, r0
-       mov r5, r1
-
-    // Remove the new allocated stack
-    bl upcall_del_stack@plt
-
-    // Restore return value
-       mov r0, r4
-       mov r1, r5
+    bl rust_stack_exhausted@plt
 
-    // Return
-    pop {r6, fp, lr}
-    mov pc, lr
+    // the above function ensures that it never returns
     .fnend
index 3c5c7644bebf7ec00112c794b774cf4a1e9ed3f5..6900444c0fe295f1b68b349f16966ab47ff2ebf0 100644 (file)
@@ -11,7 +11,6 @@
 
 .globl record_sp_limit
 .globl get_sp_limit
-.globl get_sp
 
 record_sp_limit:
        // First, try to read TLS address from coprocessor
@@ -46,7 +45,3 @@ get_sp_limit:
 
        ldr r0, [r3]
        mov pc, lr
-
-get_sp:
-       mov r0, sp
-       mov pc, lr
diff --git a/src/rt/arch/arm/regs.h b/src/rt/arch/arm/regs.h
deleted file mode 100644 (file)
index 0d1c24e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// xfail-license
-
-#define RUSTRT_RBX   0
-#define RUSTRT_RSP   1
-#define RUSTRT_RBP   2
-// RCX on Windows, RDI elsewhere
-#define RUSTRT_ARG0  3
-#define RUSTRT_R12   4
-#define RUSTRT_R13   5
-#define RUSTRT_R14   6
-#define RUSTRT_R15   7
-#define RUSTRT_IP    8
-
-#define RUSTRT_MAX  32
-
-// ARG0 is the register in which the first argument goes.
-// Naturally this depends on your operating system.
-#   define RUSTRT_ARG0_S r0
-#   define RUSTRT_ARG1_S r1
-#   define RUSTRT_ARG2_S r2
-#   define RUSTRT_ARG3_S r3
diff --git a/src/rt/arch/arm/sp.h b/src/rt/arch/arm/sp.h
deleted file mode 100644 (file)
index cd79884..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Getting the stack pointer and getting/setting sp limit.
-
-#ifndef SP_H
-#define SP_H
-
-#include "../../rust_globals.h"
-
-// Gets a pointer to the vicinity of the current stack pointer
-extern "C" uintptr_t get_sp();
-
-// Gets the pointer to the end of the Rust stack from a platform-
-// specific location in the thread control block
-extern "C" CDECL uintptr_t get_sp_limit();
-
-// Records the pointer to the end of the Rust stack in a platform-
-// specific location in the thread control block
-extern "C" CDECL void record_sp_limit(void *limit);
-
-#endif
diff --git a/src/rt/arch/i386/ccall.S b/src/rt/arch/i386/ccall.S
deleted file mode 100644 (file)
index eeee7a4..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-// Mark stack as non-executable
-#if defined(__linux__) && defined(__ELF__)
-.section       .note.GNU-stack, "", @progbits
-#endif
-
-/*
-       The function for switching to the C stack.  It is called
-       __morestack because gdb allows any frame with that name to
-       move the stack pointer to a different stack, which it usually
-       considers an error.
-*/
-
-       .text
-
-#if defined(__APPLE__) || defined(__WIN32__)
-.globl ___morestack
-___morestack:
-#else
-.globl __morestack
-.hidden __morestack
-__morestack:
-#endif
-
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__WIN32__)
-       .cfi_startproc
-#endif
-
-       pushl %ebp
-
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__WIN32__)
-       .cfi_def_cfa_offset 8
-       .cfi_offset %ebp, -8
-#endif
-
-       movl %esp,%ebp          // save esp
-
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__WIN32__)
-       .cfi_def_cfa_register %ebp
-#endif
-
-       movl 16(%ebp),%esp      // load new esp
-       subl $12,%esp           // maintain 16-byte alignment
-       pushl 8(%ebp)           // push ptr to argument block
-       calll *12(%ebp)
-       movl %ebp,%esp          // would like to use "leave" but it's slower
-       popl %ebp
-
-       ret
-
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__WIN32__)
-       .cfi_endproc
-#endif
diff --git a/src/rt/arch/i386/context.cpp b/src/rt/arch/i386/context.cpp
deleted file mode 100644 (file)
index 94e6f04..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-#include "context.h"
-#include "../../rust_globals.h"
-
-extern "C" uint32_t CDECL swap_registers(registers_t *oregs,
-                                         registers_t *regs);
-
-context::context()
-{
-    assert((void*)&regs == (void*)this);
-}
-
-void context::swap(context &out)
-{
-  swap_registers(&out.regs, &regs);
-}
-
-void context::call(void *f, void *arg, void *stack) {
-  // Get the current context, which we will then modify to call the
-  // given function.
-  swap(*this);
-
-  // set up the trampoline frame
-  uint32_t *sp = (uint32_t *)stack;
-
-  // Shift the stack pointer so the alignment works out right.
-  sp = align_down(sp) - 3;
-  *--sp = (uint32_t)arg;
-  // The final return address. 0 indicates the bottom of the stack
-  *--sp = 0;
-
-  regs.esp = (uint32_t)sp;
-  regs.eip = (uint32_t)f;
-
-  // Last base pointer on the stack should be 0
-  regs.ebp = 0;
-}
-
-#if 0
-// This is some useful code to check how the registers struct got
-// layed out in memory.
-int main() {
-  registers_t regs;
-
-  printf("Register offsets\n");
-
-#define REG(r) \
-  printf("  %6s: +%ld\n", #r, (intptr_t)&regs.r - (intptr_t)&regs);
-
-  REG(eax);
-  REG(ebx);
-  REG(ecx);
-  REG(edx);
-  REG(ebp);
-  REG(esi);
-  REG(edi);
-  REG(esp);
-
-  REG(cs);
-  REG(ds);
-  REG(ss);
-  REG(es);
-  REG(fs);
-  REG(gs);
-
-  REG(eflags);
-
-  REG(eip);
-
-  return 0;
-}
-#endif
diff --git a/src/rt/arch/i386/context.h b/src/rt/arch/i386/context.h
deleted file mode 100644 (file)
index 33352b4..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-#ifndef CONTEXT_H
-#define CONTEXT_H
-
-#include <cstdlib>
-#include <inttypes.h>
-#include <stdint.h>
-
-#include "vg/memcheck.h"
-
-template<typename T>
-T align_down(T sp)
-{
-    // There is no platform we care about that needs more than a
-    // 16-byte alignment.
-    return (T)((uint32_t)sp & ~(16 - 1));
-}
-
-struct registers_t {
-  // general purpose registers
-  uint32_t eax, ebx, ecx, edx, ebp, esi, edi, esp;
-
-  // segment registers
-  uint16_t cs, ds, ss, es, fs, gs;
-
-  uint32_t eflags;
-
-  uint32_t eip;
-} __attribute__((aligned(16)));
-
-class context {
-public:
-  registers_t regs;
-
-  context();
-
-  context *next;
-
-  void swap(context &out);
-  void call(void *f, void *arg, void *sp);
-};
-
-#endif
diff --git a/src/rt/arch/i386/gpr.cpp b/src/rt/arch/i386/gpr.cpp
deleted file mode 100644 (file)
index e5a59d6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include "gpr.h"
-
-#define LOAD(rn) do { \
-    uintptr_t tmp; \
-    asm("movl %%" #rn ",%0" : "=r" (tmp) :); \
-    this->rn = tmp; \
-} while (0)
-
-void rust_gpr::load() {
-    LOAD(eax); LOAD(ebx); LOAD(ecx); LOAD(edx);
-    LOAD(esi); LOAD(edi); LOAD(ebp); LOAD(esi);
-}
diff --git a/src/rt/arch/i386/gpr.h b/src/rt/arch/i386/gpr.h
deleted file mode 100644 (file)
index 1953170..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// General-purpose registers. This structure is used during stack crawling.
-
-#ifndef GPR_H
-#define GPR_H
-
-#include "rust_gpr_base.h"
-
-class rust_gpr : public rust_gpr_base {
-public:
-    uintptr_t eax, ebx, ecx, edx, esi, edi, ebp, eip;
-
-    inline uintptr_t get_fp() { return ebp; }
-    inline uintptr_t get_ip() { return eip; }
-
-    inline void set_fp(uintptr_t new_fp) { ebp = new_fp; }
-    inline void set_ip(uintptr_t new_ip) { eip = new_ip; }
-
-    void load();
-};
-
-#endif
index 9598f14579f752d5b02052d074792991dfc38894..25f907f479caa6148fbbfdebdb523f5b1be1b03a 100644 (file)
@@ -6,29 +6,27 @@
 /*
        __morestack
 
-       This function implements stack growth using the mechanism
-       devised by Ian Lance Taylor for gccgo, described here:
+        This function is normally used to implement stack growth using the
+        mechanism devised by Ian Lance Taylor for gccgo, described here:
 
        http://gcc.gnu.org/wiki/SplitStacks
 
-       The Rust stack is composed of a linked list of stack segments,
-       and each stack segment contains two parts: the work area,
-       where Rust functions are allowed to execute; and the red zone,
-       where no Rust code can execute, but where short runtime
-       functions (including __morestack), the dynamic linker, signal
-       handlers, and the unwinder can run.
+        Each Rust function contains an LLVM-generated prologue that compares the
+        stack space required for the current function to the space remaining in
+        the current stack segment, maintained in a platform-specific TLS slot.
+        The stack limit is strategically maintained by the Rust runtime so that
+        it is always in place whenever a Rust function is running.
 
-       Each Rust function contains an LLVM-generated prologue that
-       compares the stack space required for the current function to
-       the space remaining in the current stack segment,
-       maintained in a platform-specific TLS slot.  The stack limit
-       is strategically maintained by the Rust runtime so that it is
-       always in place whenever a Rust function is running.
+        In Rust, however, we currently do not use __morestack for stack growth
+        purposes.  Rather each task has one large stack segment. When this
+        __morestack function is run, we interpret this as a "stack overflow"
+        event rather than an event requiring an allocation of a new stack.
 
-       When there is not enough room to run the function, the function
-       prologue makes a call to __morestack to allocate a new stack
-       segment, copy any stack-based arguments to it, switch stacks,
-       then resume execution of the original function.
+        In the early days, this implementation did indeed have all of the fiddly
+        bits in order to manage split stacks in the sense of always growing
+        stacks. For posterity, the implementation can be found at commit
+        c8e77d5586aed50821e0b9361b2e24c96ade816c if we ever need to refer back
+        to it.
 
        -- The __morestack calling convention --
 
 .text
 
 #if defined(__APPLE__)
-#define RUST_GET_TASK           L_rust_get_task$stub
-#define UPCALL_NEW_STACK        L_upcall_new_stack$stub
-#define UPCALL_DEL_STACK        L_upcall_del_stack$stub
 #define MORESTACK               ___morestack
+#define EXHAUSTED               _rust_stack_exhausted
 #else
 #if defined(__linux__) || defined(__FreeBSD__)
-#define UPCALL_NEW_STACK        upcall_new_stack
-#define UPCALL_DEL_STACK        upcall_del_stack
-#define RUST_GET_TASK           rust_get_task
 #define MORESTACK               __morestack
+#define EXHAUSTED               rust_stack_exhausted
 #else
-#define UPCALL_NEW_STACK        _upcall_new_stack
-#define UPCALL_DEL_STACK        _upcall_del_stack
-#define RUST_GET_TASK           _rust_get_task
 #define MORESTACK               ___morestack
+#define EXHAUSTED               _rust_stack_exhausted
 #endif
 #endif
 
-#ifndef __APPLE__
-.globl UPCALL_NEW_STACK
-.globl UPCALL_DEL_STACK
-.globl RUST_GET_TASK
-#endif
 .globl MORESTACK
+.globl EXHAUSTED
 
 // FIXME: What about __WIN32__?
 #if defined(__linux__) || defined(__FreeBSD__)
 #endif
 
 MORESTACK:
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__WIN32__)
        .cfi_startproc
-#endif
 
        // This base pointer setup differs from most in that we are
        // telling the unwinder to consider the Canonical Frame
@@ -129,129 +115,21 @@ MORESTACK:
        // would normally be, accounting for the two arguments to
        // __morestack, and an extra return address.
 
+        // FIXME(#9854) these cfi directives don't work on windows.
+
        pushl %ebp
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__WIN32__)
        // The CFA is 20 bytes above the register that it is
        // associated with for this frame (which will be %ebp)
        .cfi_def_cfa_offset 20
        // %ebp is -20 bytes from the CFA
        .cfi_offset %ebp, -20
-#endif
        movl %esp, %ebp
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__WIN32__)
        // Calculate the CFA as an offset from %ebp
        .cfi_def_cfa_register %ebp
-#endif
-
-       // NB: This can be called with the fastcc convention so we
-       // have to preserve any argument registers
-
-       // NB: __morestack is called misaligned by 4 bytes, i.e.
-       // subl $4, %esp would get us to a normal alignment
-
-       subl $28,%esp
-
-       // Save fastcc arguments
-       movl %ecx, 16(%esp)
-       movl %edx, 12(%esp)
-
-       // FIXME (1388): it's possible we also need to save/restore some
-       // SSE2 registers here, if floats-go-in-regs on x86+SSE2. Unclear.
-
-       // FIXME (1226): main is compiled with the split-stack prologue,
-       // causing it to call __morestack, so we have to jump back out
-       calll RUST_GET_TASK
-       testl %eax,%eax
-       jz .L$bail
-
-       // The arguments to upcall_new_stack
-
-       // The size of the stack arguments to copy to the new stack,
-       // and of the arguments to __morestack
-       movl 40(%esp),%eax
-       movl %eax,8(%esp)
-       // The address of the stack arguments to the original function
-       leal 48(%esp),%eax
-       movl %eax,4(%esp)
-       // The amount of stack needed for the original function,
-       // the other argument to __morestack
-       movl 36(%esp),%eax // The amount of stack needed
-       movl %eax,(%esp)
-
-       call UPCALL_NEW_STACK
-
-       // Save the address of the new stack
-       movl %eax, (%esp)
-
-       // Grab the __morestack return pointer
-       movl 32(%esp),%eax
-       // Skip past the ret instruction in the parent fn
-       inc  %eax
-
-       // Restore the fastcc arguments to the original function
-       movl 16(%esp), %ecx
-       movl 12(%esp), %edx
-
-        // Switch stacks
-       movl (%esp),%esp
-        // Re-enter the function that called us
-       call *%eax
-
-       // Now the function that called us has returned, so we need to
-       // delete the old stack space
 
-       // Switch back to the rust stack
-       movl %ebp, %esp
+        // re-align the stack
+        subl $12,%esp
+        calll EXHAUSTED
+        // the exhaustion function guarantees that it can't return
 
-       // Realign stack - remember that __morestack was called misaligned
-       subl $12, %esp
-
-       // Save the return value of the function we allocated space for
-       movl %edx, 4(%esp)
-       movl %eax, (%esp)
-
-       call UPCALL_DEL_STACK
-
-       // And restore it
-       movl (%esp), %eax
-       movl 4(%esp), %edx
-
-       addl $12,%esp
-
-       popl %ebp
-
-       retl $8
-
-.L$bail:
-       movl 32(%esp),%eax
-       inc %eax
-
-       addl $44, %esp
-       popl %ebp
-       addl $4+8,%esp
-
-       jmpl *%eax
-
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__WIN32__)
        .cfi_endproc
-#endif
-
-#ifdef __APPLE__
-
-.section __IMPORT,__jump_table,symbol_stubs,pure_instructions+self_modifying_code,5
-
-       // Linker will replace the hlts (the ascii) with jmp
-L_rust_get_task$stub:
-       .indirect_symbol _rust_get_task
-       .ascii   "\364\364\364\364\364"
-
-L_upcall_new_stack$stub:
-       .indirect_symbol _upcall_new_stack
-       .ascii   "\364\364\364\364\364"
-
-L_upcall_del_stack$stub:
-       .indirect_symbol _upcall_del_stack
-       .ascii   "\364\364\364\364\364"
-
-       .subsections_via_symbols
-#endif
diff --git a/src/rt/arch/i386/regs.h b/src/rt/arch/i386/regs.h
deleted file mode 100644 (file)
index 85c0204..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// This file is not used by i386, but we keep it here so all
-// architectures have the same set of header files.
diff --git a/src/rt/arch/i386/sp.h b/src/rt/arch/i386/sp.h
deleted file mode 100644 (file)
index 4f4c84c..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Getting the stack pointer and getting/setting sp limit.
-
-#ifndef SP_H
-#define SP_H
-
-#include "../../rust_globals.h"
-
-// Gets a pointer to the vicinity of the current stack pointer
-extern "C" ALWAYS_INLINE uintptr_t get_sp() {
-    uintptr_t sp;
-    asm volatile (
-        "movl %%esp, %0"
-        : "=m"(sp));
-    return sp;
-}
-
-// Gets the pointer to the end of the Rust stack from a platform-
-// specific location in the thread control block
-extern "C" CDECL ALWAYS_INLINE uintptr_t get_sp_limit() {
-    uintptr_t limit;
-
-#if defined(__linux__) || defined(__FreeBSD__)
-    asm volatile (
-        "movl %%gs:48, %0"
-        : "=r"(limit));
-#elif defined(__APPLE__)
-    asm volatile (
-        "movl $0x48+90*4, %%ecx\n\t"
-        "movl %%gs:(%%ecx), %0"
-        :  "=r"(limit)
-        :: "ecx");
-#elif defined(_WIN32)
-    asm volatile (
-        "movl %%fs:0x14, %0"
-        : "=r"(limit));
-#endif
-
-    return limit;
-}
-
-// Records the pointer to the end of the Rust stack in a platform-
-// specific location in the thread control block
-extern "C" CDECL ALWAYS_INLINE void record_sp_limit(void *limit) {
-#if defined(__linux__) || defined(__FreeBSD__)
-    asm volatile (
-        "movl %0, %%gs:48"
-        :: "r"(limit));
-#elif defined(__APPLE__)
-    asm volatile (
-        "movl $0x48+90*4, %%eax\n\t"
-        "movl %0, %%gs:(%%eax)"
-        :: "r"(limit)
-        :  "eax");
-#elif defined(_WIN32)
-    asm volatile (
-        "movl %0, %%fs:0x14"
-        :: "r"(limit));
-#endif
-}
-
-#endif
diff --git a/src/rt/arch/mips/ccall.S b/src/rt/arch/mips/ccall.S
deleted file mode 100644 (file)
index cdcdc07..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// Mark stack as non-executable
-#if defined(__linux__) && defined(__ELF__)
-.section       .note.GNU-stack, "", @progbits
-#endif
-
-.text
-
-.align 2
-.globl __morestack
-.hidden __morestack
-.cfi_startproc
-.set nomips16
-.ent __morestack
-__morestack:
-        .set noreorder
-        .set nomacro
-
-        addiu $29, $29, -8
-        sw $31, 4($29)
-        sw $30, 0($29)
-
-        .cfi_def_cfa_offset 8
-        .cfi_offset 31, -4
-        .cfi_offset 30, -8
-
-        move $30, $29
-        .cfi_def_cfa_register 30
-
-        move $29, $6
-        move $25, $5
-        jalr $25
-        nop
-        move $29, $30
-
-        lw $30, 0($29)
-        lw $31, 4($29)
-        addiu $29, $29, 8
-
-        jr $31
-        nop
-.end __morestack
-.cfi_endproc
diff --git a/src/rt/arch/mips/context.cpp b/src/rt/arch/mips/context.cpp
deleted file mode 100644 (file)
index e1e5776..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include "context.h"
-#include "../../rust_globals.h"
-
-extern "C" void CDECL swap_registers(registers_t *oregs,
-                                     registers_t *regs)
-asm ("swap_registers");
-
-context::context()
-{
-    assert((void*)&regs == (void*)this);
-    memset(&regs, 0, sizeof(regs));
-}
-
-void context::swap(context &out)
-{
-    swap_registers(&out.regs, &regs);
-}
-
-void context::call(void *f, void *arg, void *stack)
-{
-  // Get the current context, which we will then modify to call the
-  // given function.
-  swap(*this);
-
-  // set up the stack
-  uint32_t *sp = (uint32_t *)stack;
-  sp = align_down(sp);
-  // The final return address. 0 indicates the bottom of the stack
-  // sp of mips o32 is 8-byte aligned
-  sp -= 2;
-  *sp = 0;
-
-  regs.data[4] = (uint32_t)arg;
-  regs.data[29] = (uint32_t)sp;
-  regs.data[25] = (uint32_t)f;
-  regs.data[31] = (uint32_t)f;
-
-  // Last base pointer on the stack should be 0
-}
diff --git a/src/rt/arch/mips/context.h b/src/rt/arch/mips/context.h
deleted file mode 100644 (file)
index 5e23644..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#ifndef CONTEXT_H
-#define CONTEXT_H
-
-#include <cstdlib>
-#include <inttypes.h>
-#include <stdint.h>
-//#include <xmmintrin.h>
-
-#include "vg/memcheck.h"
-
-template<typename T>
-T align_down(T sp)
-{
-    // There is no platform we care about that needs more than a
-    // 16-byte alignment.
-    return (T)((uint32_t)sp & ~(16 - 1));
-}
-
-// The struct in which we store the saved data.  This is mostly the
-// volatile registers and instruction pointer, but it also includes
-// RCX/RDI which are used to pass arguments.  The indices for each
-// register are found in "regs.h".  Note that the alignment must be
-// 16 bytes so that SSE instructions can be used.
-#include "regs.h"
-struct registers_t {
-    uint32_t data[RUSTRT_MAX];
-} __attribute__((aligned(16)));
-
-class context {
-public:
-    registers_t regs;
-
-    context();
-
-    context *next;
-
-    void swap(context &out);
-    void call(void *f, void *arg, void *sp);
-};
-
-#endif
diff --git a/src/rt/arch/mips/gpr.cpp b/src/rt/arch/mips/gpr.cpp
deleted file mode 100644 (file)
index da2f515..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include "gpr.h"
-
-#define LOAD(n) do { \
-    uintptr_t tmp; \
-    asm(".set noat; move %0, $" #n : "=r" (tmp) :); \
-    this->r##n = tmp; \
-} while (0)
-
-void rust_gpr::load() {
-              LOAD(1); LOAD(2); LOAD(3);
-    LOAD(4); LOAD(5); LOAD(6); LOAD(7);
-
-    LOAD(8); LOAD(9); LOAD(10); LOAD(11);
-    LOAD(12); LOAD(13); LOAD(14); LOAD(15);
-
-    LOAD(16); LOAD(17); LOAD(18); LOAD(19);
-    LOAD(20); LOAD(21); LOAD(22); LOAD(23);
-
-    LOAD(24); LOAD(25); LOAD(26); LOAD(27);
-    LOAD(28); LOAD(29); LOAD(30); LOAD(31);
-}
diff --git a/src/rt/arch/mips/gpr.h b/src/rt/arch/mips/gpr.h
deleted file mode 100644 (file)
index b48c1d4..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#ifndef GPR_H
-#define GPR_H
-
-#include "rust_gpr_base.h"
-
-class rust_gpr : public rust_gpr_base {
-public:
-    uintptr_t r0, r1, r2, r3, r4, r5, r6, r7;
-    uintptr_t r8,  r9, r10, r11, r12, r13, r14, r15;
-    uintptr_t r16, r17, r18, r19, r20, r21, r22, r23;
-    uintptr_t r24, r25, r26, r27, r28, r29, r30, r31;
-
-    inline uintptr_t get_fp() { return r30; }
-    inline uintptr_t get_ip() { return r31; }
-
-    inline void set_fp(uintptr_t new_fp) { r30 = new_fp; }
-    inline void set_ip(uintptr_t new_ip) { r31 = new_ip; }
-
-    void load();
-};
-
-#endif
index e534ac059133df53fc856009addd691871334270..9cb6ece80ce31e2f1440488d48c283df23ee2d5c 100644 (file)
@@ -3,10 +3,11 @@
 .section        .note.GNU-stack, "", @progbits
 #endif
 
+/* See i386/morestack.S for the lengthy, general explanation. */
+
 .text
 
-.globl upcall_new_stack
-.globl upcall_del_stack
+.globl rust_stack_exhausted
 .globl __morestack
 
 .hidden __morestack
@@ -18,6 +19,10 @@ __morestack:
         .set noreorder
         .set nomacro
 
+        // n.b. most of this is probably unnecessary. I know very little mips
+        //      assembly, and I didn't have anything to test on, so I wasn't
+        //      brave enough to try to trim this down.
+
         addiu $29, $29, -12
         sw $31, 8($29)
         sw $30, 4($29)
@@ -45,53 +50,11 @@ __morestack:
         move $6, $15     // The amount of stack needed
 
         move $28, $23
-        lw $25, %call16(upcall_new_stack)($23)
-        jalr $25
-        nop
-
-        // Pop the saved arguments
-        lw $4, 16($29)
-        lw $5, 20($29)
-        lw $6, 24($29)
-        lw $7, 28($29)
-        addiu $29, $29, 32
-
-        lw $24, 8($30)     // Grab the return pointer.
-        addiu $24, $24, 12 // Skip past the `lw`, `jr`, `addiu` in our parent frame
-        move $29, $2       // Switch to the new stack.
-
-        // for PIC
-        lw $2, 12($30)
-        lw $25, 16($30)
-
-        move $28, $23
-        jalr $24           // Reenter the caller function
-        nop
-
-        // Switch back to the rust stack
-        move $29, $30
-
-        // Save the return value
-        addiu $29, $29, -24
-        sw $2, 16($29)
-        sw $3, 20($29)
-
-        move $28, $23
-        lw $25, %call16(upcall_del_stack)($23)
+        lw $25, %call16(rust_stack_exhausted)($23)
         jalr $25
         nop
 
-        // Restore the return value
-        lw $2, 16($29)
-        lw $3, 20($29)
-        addiu $29, $29, 24
+        // the above function make sure that we never get here
 
-        lw $31, 8($29)
-        lw $30, 4($29)
-        lw $23, 0($29)
-        addiu $29, $29, 12
-
-        jr $31
-        nop
 .end __morestack
 .cfi_endproc
index a88fefead049fd3cc764b2a0e30e141adc291f9a..a6dfa04edbbd7e18f3c046ef1cffa53383a3b1f2 100644 (file)
@@ -38,15 +38,3 @@ get_sp_limit:
         jr $31
         nop
 .end get_sp_limit
-
-.globl get_sp
-.align 2
-.set nomips16
-.ent get_sp
-get_sp:
-        .set noreorder
-        .set nomacro
-        move $2, $29
-        jr $31
-        nop
-.end get_sp
diff --git a/src/rt/arch/mips/regs.h b/src/rt/arch/mips/regs.h
deleted file mode 100644 (file)
index 2f38e15..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#define RUSTRT_MAX  32
-
-// ARG0 is the register in which the first argument goes.
-// Naturally this depends on your operating system.
-#define RUSTRT_ARG0_S r4
-#define RUSTRT_ARG1_S r5
-#define RUSTRT_ARG2_S r6
-#define RUSTRT_ARG3_S r7
diff --git a/src/rt/arch/mips/sp.h b/src/rt/arch/mips/sp.h
deleted file mode 100644 (file)
index cd79884..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Getting the stack pointer and getting/setting sp limit.
-
-#ifndef SP_H
-#define SP_H
-
-#include "../../rust_globals.h"
-
-// Gets a pointer to the vicinity of the current stack pointer
-extern "C" uintptr_t get_sp();
-
-// Gets the pointer to the end of the Rust stack from a platform-
-// specific location in the thread control block
-extern "C" CDECL uintptr_t get_sp_limit();
-
-// Records the pointer to the end of the Rust stack in a platform-
-// specific location in the thread control block
-extern "C" CDECL void record_sp_limit(void *limit);
-
-#endif
index 857fe91c9141b85c1603cedf69433ffa78317eba..a53b1c2d737298cdfe88dbf7e64d3acbb6625da2 100644 (file)
@@ -89,12 +89,6 @@ SWAP_REGISTERS:
 #if defined(__MINGW32__) || defined(_WINDOWS)
         mov %rdi, (RUSTRT_RDI*8)(ARG0)
         mov %rsi, (RUSTRT_RSI*8)(ARG0)
-
-        // Save stack range
-        mov %gs:0x08, %r8
-        mov %r8, (RUSTRT_ST1*8)(ARG0)
-        mov %gs:0x10, %r9
-        mov %r9, (RUSTRT_ST2*8)(ARG0)
 #endif
 
         // Save 0th argument register:
@@ -134,12 +128,6 @@ SWAP_REGISTERS:
 #if defined(__MINGW32__) || defined(_WINDOWS)
         mov (RUSTRT_RDI*8)(ARG1), %rdi
         mov (RUSTRT_RSI*8)(ARG1), %rsi
-
-        // Restore stack range
-        mov (RUSTRT_ST1*8)(ARG1), %r8
-        mov %r8, %gs:0x08
-        mov (RUSTRT_ST2*8)(ARG1), %r9
-        mov %r9, %gs:0x10
 #endif
 
         // Restore 0th argument register:
diff --git a/src/rt/arch/x86_64/ccall.S b/src/rt/arch/x86_64/ccall.S
deleted file mode 100644 (file)
index dbee5bc..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-// Mark stack as non-executable
-#if defined(__linux__) && defined(__ELF__)
-.section       .note.GNU-stack, "", @progbits
-#endif
-
-/*
-       The function for switching to the C stack.  It is called
-       __morestack because gdb allows any frame with that name to
-       move the stack pointer to a different stack, which it usually
-       considers an error.
-*/
-
-#include "regs.h"
-
-#define ARG0 RUSTRT_ARG0_S
-#define ARG1 RUSTRT_ARG1_S
-#define ARG2 RUSTRT_ARG2_S
-
-        .text
-
-#if defined(__APPLE__)
-.globl ___morestack
-.private_extern MORESTACK
-___morestack:
-#elif defined(_WIN32)
-.globl __morestack
-__morestack:
-#else
-.globl __morestack
-.hidden __morestack
-__morestack:
-#endif
-
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
-       .cfi_startproc
-#endif
-
-       push %rbp
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
-       .cfi_def_cfa_offset 16
-       .cfi_offset %rbp, -16
-#endif
-
-       mov %rsp,%rbp          // save rsp
-
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
-       .cfi_def_cfa_register %rbp
-#endif
-
-       mov ARG2,%rsp          // switch stack
-       call *ARG1             // invoke target address
-       mov %rbp,%rsp
-       pop %rbp
-
-       ret
-
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
-       .cfi_endproc
-#endif
diff --git a/src/rt/arch/x86_64/context.cpp b/src/rt/arch/x86_64/context.cpp
deleted file mode 100644 (file)
index 6a265df..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-#include "context.h"
-#include "../../rust_globals.h"
-
-extern "C" void CDECL swap_registers(registers_t *oregs,
-                                     registers_t *regs);
-
-context::context()
-{
-    assert((void*)&regs == (void*)this);
-}
-
-void context::swap(context &out)
-{
-    swap_registers(&out.regs, &regs);
-}
-
-void context::call(void *f, void *arg, void *stack) {
-  // Get the current context, which we will then modify to call the
-  // given function.
-  swap(*this);
-
-  // set up the stack
-  uint64_t *sp = (uint64_t *)stack;
-  sp = align_down(sp);
-  // The final return address. 0 indicates the bottom of the stack
-  *--sp = 0;
-
-  regs.data[RUSTRT_ARG0] = (uint64_t)arg;
-  regs.data[RUSTRT_RSP] = (uint64_t)sp;
-  regs.data[RUSTRT_IP] = (uint64_t)f;
-
-  // Last base pointer on the stack should be 0
-  regs.data[RUSTRT_RBP] = 0;
-}
diff --git a/src/rt/arch/x86_64/context.h b/src/rt/arch/x86_64/context.h
deleted file mode 100644 (file)
index b768a1f..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-#ifndef CONTEXT_H
-#define CONTEXT_H
-
-#include <cstdlib>
-#include <inttypes.h>
-#include <stdint.h>
-#include <xmmintrin.h>
-
-#include "vg/memcheck.h"
-
-template<typename T>
-T align_down(T sp)
-{
-    // There is no platform we care about that needs more than a
-    // 16-byte alignment.
-    return (T)((uint64_t)sp & ~(16 - 1));
-}
-
-// The struct in which we store the saved data.  This is mostly the
-// volatile registers and instruction pointer, but it also includes
-// RCX/RDI which are used to pass arguments.  The indices for each
-// register are found in "regs.h".  Note that the alignment must be
-// 16 bytes so that SSE instructions can be used.
-#include "regs.h"
-struct registers_t {
-    uint64_t data[RUSTRT_MAX];
-} __attribute__((aligned(16)));
-
-class context {
-public:
-    registers_t regs;
-
-    context();
-
-    context *next;
-
-    void swap(context &out);
-    void call(void *f, void *arg, void *sp);
-};
-
-#endif
diff --git a/src/rt/arch/x86_64/gpr.cpp b/src/rt/arch/x86_64/gpr.cpp
deleted file mode 100644 (file)
index 37247d1..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include "gpr.h"
-
-#define LOAD(rn) do { \
-    uintptr_t tmp; \
-    asm("movq %%" #rn ",%0" : "=r" (tmp) :); \
-    this->rn = tmp; \
-} while (0)
-
-void rust_gpr::load() {
-    LOAD(rax); LOAD(rbx); LOAD(rcx); LOAD(rdx);
-    LOAD(rsi); LOAD(rdi); LOAD(rbp); LOAD(rsi);
-    LOAD(r8);  LOAD(r9);  LOAD(r10); LOAD(r11);
-    LOAD(r12); LOAD(r13); LOAD(r14); LOAD(r15);
-}
diff --git a/src/rt/arch/x86_64/gpr.h b/src/rt/arch/x86_64/gpr.h
deleted file mode 100644 (file)
index 18ef77d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// General-purpose registers. This structure is used during stack crawling.
-
-#ifndef GPR_H
-#define GPR_H
-
-#include "rust_gpr_base.h"
-
-class rust_gpr : public rust_gpr_base {
-public:
-    uintptr_t rax, rbx, rcx, rdx, rsi, rdi, rbp, rip;
-    uintptr_t  r8,  r9, r10, r11, r12, r13, r14, r15;
-
-    inline uintptr_t get_fp() { return rbp; }
-    inline uintptr_t get_ip() { return rip; }
-
-    inline void set_fp(uintptr_t new_fp) { rbp = new_fp; }
-    inline void set_ip(uintptr_t new_ip) { rip = new_ip; }
-
-    void load();
-};
-
-#endif
index b718c9121c57b8a3d30143c3f0c16508a49ce384..d248d79d12147b623fc4d008e33de4c4d5b1bc6b 100644 (file)
@@ -3,27 +3,23 @@
 .section       .note.GNU-stack, "", @progbits
 #endif
 
-/*
-       __morestack
-
-       See i386/morestack.S for the lengthy, general explanation.
-*/
+/* See i386/morestack.S for the lengthy, general explanation. */
 
 .text
 
 #if defined(__APPLE__)
-#define UPCALL_NEW_STACK        _upcall_new_stack
-#define UPCALL_DEL_STACK        _upcall_del_stack
 #define MORESTACK               ___morestack
 #else
-#define UPCALL_NEW_STACK        upcall_new_stack
-#define UPCALL_DEL_STACK        upcall_del_stack
 #define MORESTACK               __morestack
 #endif
 
-.globl UPCALL_NEW_STACK
-.globl UPCALL_DEL_STACK
-.globl MORESTACK
+#if defined(__APPLE__)
+#define EXHAUSTED               _rust_stack_exhausted
+#elif defined(__linux__) || defined(__FreeBSD__)
+#define EXHAUSTED               rust_stack_exhausted@PLT
+#else
+#define EXHAUSTED               rust_stack_exhausted
+#endif
 
 #if defined(__linux__) || defined(__FreeBSD__)
        .hidden MORESTACK
@@ -37,8 +33,7 @@
        .type MORESTACK,@function
 #endif
 
-
-#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
+.globl MORESTACK
 MORESTACK:
        .cfi_startproc
 
@@ -54,77 +49,12 @@ MORESTACK:
        // Calculate the CFA as on offset from %ebp
        .cfi_def_cfa_register %rbp
 
-        subq $56, %rsp
-
-       // Save argument registers of the original function
-       movq %rdi,       (%rsp)
-       movq %rsi,      8(%rsp)
-       movq %rdx,     16(%rsp)
-       movq %rcx,     24(%rsp)
-       movq %r8,      32(%rsp)
-       movq %r9,      40(%rsp)
-
-       // Calculate the address of the stack arguments.
-       // We have the base pointer, __morestack's return address,
-       // and __morestack's caller's return address to skip
-       movq %rbp, %rax
-       addq $24, %rax  // Base pointer, return address x2
-
-       // The arguments to __morestack are passed in %r10 & %r11
-
-       movq %r11, %rdx // Size of stack arguments
-       movq %rax, %rsi // Address of stack arguments
-       movq %r10, %rdi // The amount of stack needed
-
-#ifdef __APPLE__
-       call UPCALL_NEW_STACK
-#endif
-#ifdef __linux__
-       call UPCALL_NEW_STACK@PLT
-#endif
-#ifdef __FreeBSD__
-       call UPCALL_NEW_STACK@PLT
-#endif
-
-       // Pop the saved arguments
-       movq      (%rsp), %rdi
-       movq     8(%rsp), %rsi
-       movq    16(%rsp), %rdx
-       movq    24(%rsp), %rcx
-       movq    32(%rsp), %r8
-       movq    40(%rsp), %r9
-
-       addq $56, %rsp
-
-        movq 8(%rbp),%r10       // Grab the return pointer.
-        incq %r10               // Skip past the `ret` in our parent frame
-        movq %rax,%rsp          // Switch to the new stack.
-
-        call *%r10              // Reenter the caller function
-
-       // Switch back to the rust stack
-       movq %rbp, %rsp
-
-       // Save the return value
-       pushq %rax
+        // re-align the stack
+        subq $8, %rsp
 
-#ifdef __APPLE__
-       call UPCALL_DEL_STACK
-#endif
-#ifdef __linux__
-       call UPCALL_DEL_STACK@PLT
-#endif
-#ifdef __FreeBSD__
-       call UPCALL_DEL_STACK@PLT
-#endif
+        // kill this program
+        call EXHAUSTED
 
-       popq %rax // Restore the return value
-       popq %rbp
-       ret
+        // the exhaustion function guarantees that it can't return
 
        .cfi_endproc
-
-#else
-MORESTACK:
-       ret
-#endif
index cff47ac378af0e192a739b9382206865263ed52c..25160ca68a6b398d526f71e5c55492d24385706e 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// This is loosely kept in sync with src/libstd/rt/context.rs
+
 #define RUSTRT_RBX   0
 #define RUSTRT_RSP   1
 #define RUSTRT_RBP   2
diff --git a/src/rt/arch/x86_64/sp.h b/src/rt/arch/x86_64/sp.h
deleted file mode 100644 (file)
index 7649277..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Getting the stack pointer and getting/setting sp limit.
-
-#ifndef SP_H
-#define SP_H
-
-#include "../../rust_globals.h"
-
-// Gets a pointer to the vicinity of the current stack pointer
-extern "C" ALWAYS_INLINE uintptr_t get_sp() {
-    uintptr_t sp;
-    asm volatile (
-        "movq %%rsp, %0"
-        : "=m"(sp));
-    return sp;
-}
-
-// Gets the pointer to the end of the Rust stack from a platform-
-// specific location in the thread control block
-extern "C" CDECL ALWAYS_INLINE uintptr_t get_sp_limit() {
-    uintptr_t limit;
-
-#if defined(__linux__)
-    asm volatile (
-        "movq %%fs:112, %0"
-        : "=r"(limit));
-#elif defined(__APPLE__)
-    asm volatile (
-        "movq $0x60+90*8, %%rsi\n\t"
-        "movq %%gs:(%%rsi), %0"
-        :  "=r"(limit)
-        :: "rsi");
-#elif defined(__FreeBSD__)
-    asm volatile (
-        "movq %%fs:24, %0"
-        : "=r"(limit));
-#elif defined(_WIN64)
-    asm volatile (
-        "movq %%gs:0x28, %0"
-        : "=r"(limit));
-#endif
-
-    return limit;
-}
-
-// Records the pointer to the end of the Rust stack in a platform-
-// specific location in the thread control block
-extern "C" CDECL ALWAYS_INLINE void record_sp_limit(void *limit) {
-#if defined(__linux__)
-    asm volatile (
-        "movq %0, %%fs:112"
-        :: "r"(limit));
-#elif defined(__APPLE__)
-    asm volatile (
-        "movq $0x60+90*8, %%rsi\n\t"
-        "movq %0, %%gs:(%%rsi)"
-        :: "r"(limit)
-        :  "rsi");
-#elif defined(__FreeBSD__)
-    asm volatile (
-        "movq %0, %%fs:24"
-        :: "r"(limit));
-#elif defined(_WIN64)
-    asm volatile (
-        "movq %0, %%gs:0x28"
-        :: "r"(limit));
-#endif
-}
-
-#endif
index 9750e22e9453b685a3896e26ddbe506ae6aefa81..755235a9138dc20771385bdf72ac5874f4e52d31 100644 (file)
@@ -16,7 +16,6 @@
 #include "memory_region.h"
 #include "boxed_region.h"
 #include "vg/valgrind.h"
-#include "sp.h"
 
 #include <time.h>
 
@@ -340,22 +339,26 @@ rust_unlock_little_lock(lock_and_signal *lock) {
     lock->unlock();
 }
 
+typedef void(startfn)(void*, void*);
+
 class raw_thread: public rust_thread {
 public:
-    fn_env_pair fn;
+    startfn *raw_start;
+    void *rust_fn;
+    void *rust_env;
 
-    raw_thread(fn_env_pair fn) : fn(fn) { }
+    raw_thread(startfn *raw_start, void *rust_fn, void *rust_env)
+        : raw_start(raw_start), rust_fn(rust_fn), rust_env(rust_env) { }
 
     virtual void run() {
-        record_sp_limit(0);
-        fn.f(fn.env, NULL);
+        raw_start(rust_fn, rust_env);
     }
 };
 
 extern "C" raw_thread*
-rust_raw_thread_start(fn_env_pair *fn) {
-    assert(fn);
-    raw_thread *thread = new raw_thread(*fn);
+rust_raw_thread_start(startfn *raw_start, void *rust_start, void *rust_env) {
+    assert(raw_start && rust_start);
+    raw_thread *thread = new raw_thread(raw_start, rust_start, rust_env);
     thread->start();
     return thread;
 }
@@ -552,12 +555,6 @@ rust_get_global_args_ptr() {
     return &global_args_ptr;
 }
 
-// Used by i386 __morestack
-extern "C" CDECL uintptr_t
-rust_get_task() {
-    return 0;
-}
-
 static lock_and_signal env_lock;
 
 extern "C" CDECL void
diff --git a/src/rt/rust_gpr_base.h b/src/rt/rust_gpr_base.h
deleted file mode 100644 (file)
index 7ec2dda..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Base class for architecture-specific general-purpose registers. This
-// structure is used during stack crawling.
-
-#ifndef GPR_BASE_H
-#define GPR_BASE_H
-
-#include <stdint.h>
-
-class rust_gpr_base {
-public:
-    // Returns the value of a register by number.
-    inline uintptr_t &get(uint32_t i) {
-        return reinterpret_cast<uintptr_t *>(this)[i];
-    }
-
-    // Sets the value of a register by number.
-    inline void set(uint32_t i, uintptr_t val) {
-        reinterpret_cast<uintptr_t *>(this)[i] = val;
-    }
-};
-
-
-#endif
index f10a1f36938a30cc9a73834e997ab06535db1438..3c6e2d68c2fed274be5979a70604f10bd40f4478 100644 (file)
@@ -11,7 +11,6 @@
 // Helper functions used only in tests
 
 #include "rust_util.h"
-#include "sync/rust_thread.h"
 #include "sync/lock_and_signal.h"
 
 // These functions are used in the unit tests for C ABI calls.
index fb9934c76011dcf3295dd438e2165cc59248d9d2..aa545c3cdba0842084f6ee5b209e6e9a3866ae52 100644 (file)
@@ -181,7 +181,6 @@ rust_get_global_args_ptr
 rust_take_global_args_lock
 rust_drop_global_args_lock
 rust_get_test_int
-rust_get_task
 rust_uv_get_loop_from_getaddrinfo_req
 rust_uv_spawn
 rust_uv_process_kill
index 824642fc435d02625550d1a03f51608e09cae4fa..a78153523d2529bde99ccaf83b2de4da7366fb33 100644 (file)
 
 const size_t default_stack_sz = 1024*1024;
 
-rust_thread::rust_thread() : thread(0), stack_sz(default_stack_sz) {
-}
-
-rust_thread::rust_thread(size_t stack_sz)
-  : thread(0), stack_sz(stack_sz) {
+rust_thread::rust_thread() : thread(0) {
 }
 
 rust_thread::~rust_thread() {
@@ -40,10 +36,11 @@ rust_thread_start(void *ptr) {
 void
 rust_thread::start() {
 #if defined(__WIN32__)
-   thread = CreateThread(NULL, stack_sz, rust_thread_start, this, 0, NULL);
+   thread = CreateThread(NULL, default_stack_sz, rust_thread_start, this, 0, NULL);
 #else
    // PTHREAD_STACK_MIN of some system is larger than default size
    // so we check stack_sz to prevent assertion failure.
+   size_t stack_sz = default_stack_sz;
    if (stack_sz < PTHREAD_STACK_MIN) {
       stack_sz = PTHREAD_STACK_MIN;
    }
index 212d237698e94da44589a0f405269b9958c6962d..cad87e514b5c831f9f24d3d26738125dd1605059 100644 (file)
@@ -23,11 +23,9 @@ class rust_thread {
 #else
     pthread_t thread;
 #endif
-    size_t stack_sz;
  public:
 
     rust_thread();
-    rust_thread(size_t stack_sz);
     virtual ~rust_thread();
 
     void start();
index d46ccf299e822550294f2008ba1e6fcff3cd7dff..e6fe8615a96280c885c3a0971bed1bd492f2c3ec 100644 (file)
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #[crate_type = "lib"];
-#[no_std];
 
 static private: int = 0;
 pub static public: int = 0;
index f447a6c547c7bb7774eac47bd271d24b83134f31..24a2b561a8b0b1962caac732b2b74efe695725d9 100644 (file)
@@ -10,8 +10,6 @@
 
 // aux-build:static_priv_by_default.rs
 
-#[no_std];
-
 extern mod static_priv_by_default;
 
 mod child {
index ca1221e7432f571381361fd3e4c218e250e2f332..8dd05cd00da2c510e102c267c3eba338e36e188a 100644 (file)
 
 // aux-build:static_priv_by_default.rs
 
-#[no_std]; // helps if debugging resolve
-
 extern mod static_priv_by_default;
 
 fn foo<T>() {}
 
-#[start]
-fn main(_: int, _: **u8) -> int {
+fn main() {
     // Actual public items should be public
     static_priv_by_default::a;
     static_priv_by_default::b;
@@ -49,6 +46,4 @@ fn main(_: int, _: **u8) -> int {
     //~^ ERROR: struct `c` is private
     foo::<static_priv_by_default::foo::d>();
     //~^ ERROR: type `d` is private
-
-    3
 }
index 104e33b7488e07edafbfc92433f8bfca56f97eaa..f69f53cecd47865570778b3b7f6cb412841297d6 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-fast
+// xfail-test #9839
 // aux-build:no_std_crate.rs
 
 // This tests that crates which link to std can also be linked to crates with