From 7bf41392b62f8e118ac21842804808c516b953b0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Dec 2011 15:12:36 -0800 Subject: [PATCH 01/15] correct the use of 'sed -i' --- src/etc/gen-intrinsics | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/etc/gen-intrinsics b/src/etc/gen-intrinsics index 757df61596c7..660c367991b6 100755 --- a/src/etc/gen-intrinsics +++ b/src/etc/gen-intrinsics @@ -17,10 +17,11 @@ do -Isrc/rt/arch/$ARCH -fno-stack-protector \ -o src/rt/intrinsics/intrinsics.$ARCH.ll.in \ src/rt/intrinsics/intrinsics.cpp - sed -i \ + sed -i .orig \ -e 's/^target datalayout =/; target datalayout =/' \ src/rt/intrinsics/intrinsics.$ARCH.ll.in - sed -i \ + sed -i .orig \ -e 's/^target triple = "[^"]*"/target triple = "@CFG_TARGET_TRIPLE@"/' \ src/rt/intrinsics/intrinsics.$ARCH.ll.in -done \ No newline at end of file + rm src/rt/intrinsics/intrinsics.$ARCH.ll.in.orig +done From 9a738fd61d3006796d518ba751f5bb632f65edb6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Dec 2011 16:26:47 -0800 Subject: [PATCH 02/15] rt: Various tweaks to make __morestack unwinding work on linux When unwinding through __morestack the stack limit in the TLS is invalidated and must be reset. Instead of actually landing at __morestack we're just going to make all our Rust landing pads call upcall_reset_stack_limit, which will find the stack segment that corresponds to the current stack pointer and put the limit in the TLS. Also massively expand the stack segment red zone to make more room for the dynamic linker. Will fix in the future. --- src/comp/back/upcall.rs | 6 ++++-- src/comp/middle/trans.rs | 5 +++++ src/rt/arch/i386/record_sp.S | 7 +++++++ src/rt/arch/x86_64/morestack.S | 4 ++++ src/rt/arch/x86_64/record_sp.S | 7 +++++++ src/rt/rust_task.cpp | 27 +++++++++++++++++++++++++-- src/rt/rust_task.h | 1 + src/rt/rust_upcall.cpp | 9 +++++++++ src/rt/rustrt.def.in | 1 + src/test/run-fail/morestack3.rs | 4 ++-- 10 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index 419a7fdc34c2..71f33ccb3729 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -27,7 +27,8 @@ dynastack_free: ValueRef, alloc_c_stack: ValueRef, call_shim_on_c_stack: ValueRef, - rust_personality: ValueRef}; + rust_personality: ValueRef, + reset_stack_limit: ValueRef}; fn declare_upcalls(targ_cfg: @session::config, _tn: type_names, @@ -89,7 +90,8 @@ fn decl(llmod: ModuleRef, name: str, tys: [TypeRef], rv: TypeRef) -> // arguments: void *args, void *fn_ptr [T_ptr(T_i8()), T_ptr(T_i8())], int_t), - rust_personality: d("rust_personality", [], T_i32()) + rust_personality: d("rust_personality", [], T_i32()), + reset_stack_limit: dv("reset_stack_limit", []) }; } // diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 6804434bb4ce..41df1b28edd5 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3904,6 +3904,11 @@ fn trans_landing_pad(bcx: @block_ctxt, // The landing pad block is a cleanup SetCleanup(bcx, llpad); + // Because we may have unwound across a stack boundary, we must call into + // the runtime to figure out which stack segment we are on and place the + // stack limit back into the TLS. + Call(bcx, bcx_ccx(bcx).upcalls.reset_stack_limit, []); + // FIXME: This seems like a very naive and redundant way to generate the // landing pads, as we're re-generating all in-scope cleanups for each // function call. Probably good optimization opportunities here. diff --git a/src/rt/arch/i386/record_sp.S b/src/rt/arch/i386/record_sp.S index 153225e8187b..3f299de5d154 100644 --- a/src/rt/arch/i386/record_sp.S +++ b/src/rt/arch/i386/record_sp.S @@ -2,11 +2,14 @@ #if defined(__APPLE__) || defined(_WIN32) #define RECORD_SP _record_sp +#define GET_SP _get_sp #else #define RECORD_SP record_sp +#define GET_SP get_sp #endif .globl RECORD_SP +.globl GET_SP #if defined(__linux__) RECORD_SP: @@ -25,3 +28,7 @@ RECORD_SP: ret #endif #endif + +GET_SP: + movl %esp, %eax + ret \ No newline at end of file diff --git a/src/rt/arch/x86_64/morestack.S b/src/rt/arch/x86_64/morestack.S index ef0edcee7209..535b6190f1c2 100644 --- a/src/rt/arch/x86_64/morestack.S +++ b/src/rt/arch/x86_64/morestack.S @@ -132,6 +132,10 @@ MORESTACK: addq $8, %rsp popq %rbp +#ifdef __linux__ + .cfi_restore %rbp + .cfi_def_cfa %rsp, 8 +#endif ret #if defined(__ELF__) diff --git a/src/rt/arch/x86_64/record_sp.S b/src/rt/arch/x86_64/record_sp.S index e8284c5fac9a..415f6685655c 100644 --- a/src/rt/arch/x86_64/record_sp.S +++ b/src/rt/arch/x86_64/record_sp.S @@ -2,11 +2,14 @@ #if defined(__APPLE__) || defined(_WIN32) #define RECORD_SP _record_sp +#define GET_SP _get_sp #else #define RECORD_SP record_sp +#define GET_SP get_sp #endif .globl RECORD_SP +.globl GET_SP #if defined(__linux__) RECORD_SP: @@ -23,3 +26,7 @@ RECORD_SP: ret #endif #endif + +GET_SP: + movq %rsp, %rax + ret diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index b540225243f9..888c9ac701ae 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -18,11 +18,11 @@ // to the rt, compiler and dynamic linker for running small functions // FIXME: We want this to be 128 but need to slim the red zone calls down #ifdef __i386__ -#define RED_ZONE_SIZE 2048 +#define RED_ZONE_SIZE 65536 #endif #ifdef __x86_64__ -#define RED_ZONE_SIZE 2048 +#define RED_ZONE_SIZE 65536 #endif // Stack size @@ -613,6 +613,29 @@ rust_task::record_stack_limit() { "Stack size must be greater than LIMIT_OFFSET"); record_sp(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE); } + +extern "C" uintptr_t get_sp(); + +/* +Called by landing pads during unwinding to figure out which +stack segment we are currently running on, delete the others, +and record the stack limit (which was not restored when unwinding +through __morestack). + */ +void +rust_task::reset_stack_limit() { + uintptr_t sp = get_sp(); + // Not positive these bounds for sp are correct. + // I think that the first possible value for esp on a new + // stack is stk->limit, which points one word in front of + // the first work to be pushed onto a new stack. + while (sp <= (uintptr_t)stk->data || stk->limit < sp) { + del_stk(this, stk); + A(sched, stk != NULL, "Failed to find the current stack"); + } + record_stack_limit(); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 00a9fc277dc7..474728015101 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -200,6 +200,7 @@ rust_task : public kernel_owned, rust_cond void *new_stack(size_t stk_sz, void *args_addr, size_t args_sz); void del_stack(); void record_stack_limit(); + void reset_stack_limit(); }; // diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 653db471fc01..5a4c37c500cd 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -259,6 +259,15 @@ upcall_del_stack() { task->del_stack(); } +// Landing pads need to call this to insert the +// correct limit into TLS. +// NB: This must be called on the Rust stack +extern "C" CDECL void +upcall_reset_stack_limit() { + rust_task *task = rust_scheduler::get_task(); + task->reset_stack_limit(); +} + extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index ba1a9c1403da..306c750c8fbb 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -69,6 +69,7 @@ upcall_vec_push upcall_call_shim_on_c_stack upcall_new_stack upcall_del_stack +upcall_reset_stack_limit asm_call_on_stack rust_uv_default_loop rust_uv_loop_new diff --git a/src/test/run-fail/morestack3.rs b/src/test/run-fail/morestack3.rs index 9fdd0326b661..9796017a8eb0 100644 --- a/src/test/run-fail/morestack3.rs +++ b/src/test/run-fail/morestack3.rs @@ -25,10 +25,10 @@ fn getbig(i: int) { getbig(i - 1); } } - getbig(1000); + getbig(100); } fn main() { rustrt::set_min_stack(256u); - std::task::spawn(1000, getbig_and_fail); + std::task::spawn(100, getbig_and_fail); } \ No newline at end of file From 15d60326f67e84608ff8b2ffe1984d9b4d600ba6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 6 Dec 2011 14:02:03 -0800 Subject: [PATCH 03/15] helpful targets --- Makefile.in | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index ec08f124b728..aab593f3046a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -353,12 +353,24 @@ $(foreach build,$(CFG_TARGET_TRIPLES), \ # Builds a functional Rustc for the given host. ###################################################################### +define DEF_RUSTC_STAGE_TARGET +# $(1) == architecture +# $(2) == stage + +rustc-stage$(2)-H-$(1): \ + $$(foreach target,$$(CFG_TARGET_TRIPLES), \ + $$(SREQ$(2)_T_$$(target)_H_$(1))) + +endef + +$(foreach host,$(CFG_TARGET_TRIPLES), \ + $(eval $(foreach stage,1 2 3, \ + $(eval $(call DEF_RUSTC_STAGE_TARGET,$(host),$(stage)))))) + define DEF_RUSTC_TARGET # $(1) == architecture -rustc-H-$(1): \ - $$(foreach target,$$(CFG_TARGET_TRIPLES), \ - $$(SREQ3_T_$$(target)_H_$(1))) +rustc-H-$(1): rustc-stage3-H-$(1) endef $(foreach host,$(CFG_TARGET_TRIPLES), \ From aa99bfa170971b14bb72a10ef153480ec4caaa46 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 6 Dec 2011 14:02:06 -0800 Subject: [PATCH 04/15] do not stringify AST nodes unless emitting comments --- src/comp/middle/trans.rs | 4 +++- src/comp/middle/trans_build.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 41df1b28edd5..693c8ae79e82 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -4536,7 +4536,9 @@ fn zero_alloca(cx: @block_ctxt, llptr: ValueRef, t: ty::t) fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt { // FIXME Fill in cx.sp - add_span_comment(cx, s.span, stmt_to_str(s)); + if (!bcx_ccx(cx).sess.get_opts().no_asm_comments) { + add_span_comment(cx, s.span, stmt_to_str(s)); + } let bcx = cx; alt s.node { diff --git a/src/comp/middle/trans_build.rs b/src/comp/middle/trans_build.rs index 02894769ae69..b7756b0902d8 100644 --- a/src/comp/middle/trans_build.rs +++ b/src/comp/middle/trans_build.rs @@ -515,7 +515,9 @@ fn add_span_comment(bcx: @block_ctxt, sp: span, text: str) { fn add_comment(bcx: @block_ctxt, text: str) { let ccx = bcx_ccx(bcx); if (!ccx.sess.get_opts().no_asm_comments) { - let comment_text = "; " + text; + check str::is_not_empty("$"); + let sanitized = str::replace(text, "$", ""); + let comment_text = "; " + sanitized; let asm = str::as_buf(comment_text, { |c| str::as_buf("", { |e| llvm::LLVMConstInlineAsm(T_fn([], T_void()), c, e, 0, 0)})}); From 66355607da4a2491e4a75dc6e0d2036120f0ede2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 6 Dec 2011 15:55:11 -0800 Subject: [PATCH 05/15] hack for now: map uint hashes into a u32, which helps x86_64 perf. --- src/libstd/map.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/libstd/map.rs b/src/libstd/map.rs index c802b5b889ff..a4ef46740174 100644 --- a/src/libstd/map.rs +++ b/src/libstd/map.rs @@ -137,21 +137,25 @@ fn make_buckets(nbkts: uint) -> [mutable bucket] { // is always a power of 2), so that all buckets are probed for a // fixed key. - fn hashl(n: uint, _nbkts: uint) -> uint { ret (n >>> 16u) * 2u + 1u; } - fn hashr(n: uint, _nbkts: uint) -> uint { ret 0x0000_ffff_u & n; } - fn hash(h: uint, nbkts: uint, i: uint) -> uint { - ret (hashl(h, nbkts) * i + hashr(h, nbkts)) % nbkts; + fn hashl(n: u32) -> u32 { ret (n >>> 16u32) * 2u32 + 1u32; } + fn hashr(n: u32) -> u32 { ret 0x0000_ffff_u32 & n; } + fn hash(h: u32, nbkts: uint, i: uint) -> uint { + ret ((hashl(h) as uint) * i + (hashr(h) as uint)) % nbkts; } + + fn to_u64(h: uint) -> u32 { + ret (h as u32) ^ ((h >>> 16u) as u32); + } + /** * We attempt to never call this with a full table. If we do, it * will fail. */ - fn insert_common(hasher: hashfn, eqer: eqfn, bkts: [mutable bucket], nbkts: uint, key: K, val: V) -> bool { let i: uint = 0u; - let h: uint = hasher(key); + let h = to_u64(hasher(key)); while i < nbkts { let j: uint = hash(h, nbkts, i); alt bkts[j] { @@ -171,7 +175,7 @@ fn find_common(hasher: hashfn, eqer: eqfn, bkts: [mutable bucket], nbkts: uint, key: K) -> option::t { let i: uint = 0u; - let h: uint = hasher(key); + let h = to_u64(hasher(key)); while i < nbkts { let j: uint = hash(h, nbkts, i); alt bkts[j] { @@ -244,7 +248,7 @@ fn find(key: K) -> option::t { } fn remove(key: K) -> option::t { let i: uint = 0u; - let h: uint = hasher(key); + let h = to_u64(hasher(key)); while i < nbkts { let j: uint = hash(h, nbkts, i); alt bkts[j] { From 8b608125ac2d59cace17fc3f177d13e2a0021716 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 6 Dec 2011 21:34:50 -0800 Subject: [PATCH 06/15] fix hash function: + binds tighter than << --- src/comp/syntax/ast_util.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index e9b89b59cd51..f39b5865c251 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -193,7 +193,10 @@ fn is_constraint_arg(e: @expr) -> bool { fn eq_ty(&&a: @ty, &&b: @ty) -> bool { ret std::box::ptr_eq(a, b); } -fn hash_ty(&&t: @ty) -> uint { ret t.span.lo << 16u + t.span.hi; } +fn hash_ty(&&t: @ty) -> uint { + let res = (t.span.lo << 16u) + t.span.hi; + ret res; +} fn hash_def_id(&&id: def_id) -> uint { id.crate as uint << 16u + (id.node as uint) From 9b7347dd9648fd4cdf134700ec35bc370022da2b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Dec 2011 19:04:35 -0800 Subject: [PATCH 07/15] modify upcalls to take structs as args --- src/rt/rust_upcall.cpp | 344 ++++++++++++++++++++++++++++++----------- 1 file changed, 256 insertions(+), 88 deletions(-) diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 5a4c37c500cd..40cb35f0149d 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -6,7 +6,31 @@ #include "rust_upcall.h" #include -// Upcalls. +extern "C" void record_sp(void *limit); + +/** + * Switches to the C-stack and invokes |fn_ptr|, passing |args| as argument. + */ +extern "C" CDECL void +upcall_call_shim_on_c_stack(void *args, void *fn_ptr) { + rust_task *task = rust_scheduler::get_task(); + + // FIXME (1226) - The shim functions generated by rustc contain the + // morestack prologue, so we need to let them know they have enough + // stack. + record_sp(0); + + rust_scheduler *sched = task->sched; + try { + sched->c_context.call_shim_on_c_stack(args, fn_ptr); + } catch (...) { + task = rust_scheduler::get_task(); + task->record_stack_limit(); + throw; + } + task = rust_scheduler::get_task(); + task->record_stack_limit(); +} #if defined(__i386__) || defined(__x86_64__) || defined(_M_X64) void @@ -47,24 +71,34 @@ copy_elements(rust_task *task, type_desc *elem_t, } } +struct s_fail_args { + char const *expr; + char const *file; + size_t line; +}; + extern "C" CDECL void -upcall_fail(char const *expr, - char const *file, - size_t line) { +upcall_s_fail(s_fail_args *args) { rust_task *task = rust_scheduler::get_task(); LOG_UPCALL_ENTRY(task); - LOG_ERR(task, upcall, "upcall fail '%s', %s:%" PRIdPTR, expr, file, line); + LOG_ERR(task, upcall, "upcall fail '%s', %s:%" PRIdPTR, + args->expr, args->file, args->line); task->fail(); } +struct s_malloc_args { + size_t nbytes; + type_desc *td; +}; + extern "C" CDECL uintptr_t -upcall_malloc(size_t nbytes, type_desc *td) { +upcall_s_malloc(s_malloc_args *args) { rust_task *task = rust_scheduler::get_task(); LOG_UPCALL_ENTRY(task); LOG(task, mem, "upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ")", - nbytes, td); + args->nbytes, args->td); gc::maybe_gc(task); cc::maybe_cc(task); @@ -72,107 +106,136 @@ upcall_malloc(size_t nbytes, type_desc *td) { // TODO: Maybe use dladdr here to find a more useful name for the // type_desc. - void *p = task->malloc(nbytes, "tdesc", td); - memset(p, '\0', nbytes); + void *p = task->malloc(args->nbytes, "tdesc", args->td); + memset(p, '\0', args->nbytes); - task->local_allocs[p] = td; + task->local_allocs[p] = args->td; debug::maybe_track_origin(task, p); LOG(task, mem, "upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ") = 0x%" PRIxPTR, - nbytes, td, (uintptr_t)p); + args->nbytes, args->td, (uintptr_t)p); return (uintptr_t) p; } +struct s_free_args { + void *ptr; + uintptr_t is_gc; +}; + /** * Called whenever an object's ref count drops to zero. */ extern "C" CDECL void -upcall_free(void* ptr, uintptr_t is_gc) { +upcall_s_free(s_free_args *args) { rust_task *task = rust_scheduler::get_task(); LOG_UPCALL_ENTRY(task); rust_scheduler *sched = task->sched; DLOG(sched, mem, "upcall free(0x%" PRIxPTR ", is_gc=%" PRIdPTR ")", - (uintptr_t)ptr, is_gc); + (uintptr_t)args->ptr, args->is_gc); - task->local_allocs.erase(ptr); - debug::maybe_untrack_origin(task, ptr); + task->local_allocs.erase(args->ptr); + debug::maybe_untrack_origin(task, args->ptr); - task->free(ptr, (bool) is_gc); + task->free(args->ptr, (bool) args->is_gc); } +struct s_shared_malloc_args { + size_t nbytes; + type_desc *td; +}; + extern "C" CDECL uintptr_t -upcall_shared_malloc(size_t nbytes, type_desc *td) { +upcall_s_shared_malloc(s_shared_malloc_args *args) { rust_task *task = rust_scheduler::get_task(); LOG_UPCALL_ENTRY(task); LOG(task, mem, - "upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR ")", - nbytes, td); - void *p = task->kernel->malloc(nbytes, "shared malloc"); - memset(p, '\0', nbytes); + "upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR ")", + args->nbytes, args->td); + void *p = task->kernel->malloc(args->nbytes, "shared malloc"); + memset(p, '\0', args->nbytes); LOG(task, mem, - "upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR - ") = 0x%" PRIxPTR, - nbytes, td, (uintptr_t)p); + "upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR + ") = 0x%" PRIxPTR, + args->nbytes, args->td, (uintptr_t)p); return (uintptr_t) p; } +struct s_shared_free_args { + void *ptr; +}; + /** * Called whenever an object's ref count drops to zero. */ extern "C" CDECL void -upcall_shared_free(void* ptr) { +upcall_s_shared_free(s_shared_free_args *args) { rust_task *task = rust_scheduler::get_task(); LOG_UPCALL_ENTRY(task); rust_scheduler *sched = task->sched; DLOG(sched, mem, "upcall shared_free(0x%" PRIxPTR")", - (uintptr_t)ptr); - task->kernel->free(ptr); + (uintptr_t)args->ptr); + task->kernel->free(args->ptr); } +struct s_get_type_desc_args { + size_t size; + size_t align; + size_t n_descs; + type_desc const **descs; + uintptr_t n_obj_params; +}; + extern "C" CDECL type_desc * -upcall_get_type_desc(void *curr_crate, // ignored, legacy compat. - size_t size, - size_t align, - size_t n_descs, - type_desc const **descs, - uintptr_t n_obj_params) { +upcall_s_get_type_desc(s_get_type_desc_args *args) { rust_task *task = rust_scheduler::get_task(); check_stack(task); LOG_UPCALL_ENTRY(task); LOG(task, cache, "upcall get_type_desc with size=%" PRIdPTR - ", align=%" PRIdPTR ", %" PRIdPTR " descs", size, align, - n_descs); + ", align=%" PRIdPTR ", %" PRIdPTR " descs", args->size, args->align, + args->n_descs); rust_crate_cache *cache = task->get_crate_cache(); - type_desc *td = cache->get_type_desc(size, align, n_descs, descs, - n_obj_params); + type_desc *td = cache->get_type_desc(args->size, args->align, args->n_descs, + args->descs, args->n_obj_params); LOG(task, cache, "returning tydesc 0x%" PRIxPTR, td); return td; } -extern "C" CDECL void -upcall_vec_grow(rust_vec** vp, size_t new_sz) { - rust_task *task = rust_scheduler::get_task(); - LOG_UPCALL_ENTRY(task); - reserve_vec(task, vp, new_sz); - (*vp)->fill = new_sz; -} +struct s_vec_grow_args { + rust_vec** vp; + size_t new_sz; +}; extern "C" CDECL void -upcall_vec_push(rust_vec** vp, type_desc* elt_ty, void* elt) { +upcall_s_vec_grow(s_vec_grow_args *args) { rust_task *task = rust_scheduler::get_task(); LOG_UPCALL_ENTRY(task); - size_t new_sz = (*vp)->fill + elt_ty->size; - reserve_vec(task, vp, new_sz); - rust_vec* v = *vp; - copy_elements(task, elt_ty, &v->data[0] + v->fill, elt, elt_ty->size); - v->fill += elt_ty->size; + reserve_vec(task, args->vp, args->new_sz); + (*args->vp)->fill = args->new_sz; +} + +struct s_vec_push_args { + rust_vec** vp; + type_desc* elt_ty; + void* elt; +}; + +extern "C" CDECL void +upcall_s_vec_push(s_vec_push_args *args) { + rust_task *task = rust_scheduler::get_task(); + LOG_UPCALL_ENTRY(task); + size_t new_sz = (*args->vp)->fill + args->elt_ty->size; + reserve_vec(task, args->vp, new_sz); + rust_vec* v = *args->vp; + copy_elements(task, args->elt_ty, &v->data[0] + v->fill, + args->elt, args->elt_ty->size); + v->fill += args->elt_ty->size; } /** @@ -180,60 +243,49 @@ upcall_vec_push(rust_vec** vp, type_desc* elt_ty, void* elt) { * space in the dynamic stack. */ extern "C" CDECL void * -upcall_dynastack_mark() { +upcall_s_dynastack_mark() { return rust_scheduler::get_task()->dynastack.mark(); } +struct s_dynastack_alloc_args { + size_t sz; +}; + /** * Allocates space in the dynamic stack and returns it. * * FIXME: Deprecated since dynamic stacks need to be self-describing for GC. */ extern "C" CDECL void * -upcall_dynastack_alloc(size_t sz) { +upcall_s_dynastack_alloc(s_dynastack_alloc_args *args) { + size_t sz = args->sz; return sz ? rust_scheduler::get_task()->dynastack.alloc(sz, NULL) : NULL; } +struct s_dynastack_alloc_2_args { + size_t sz; + type_desc *ty; +}; + /** * Allocates space associated with a type descriptor in the dynamic stack and * returns it. */ extern "C" CDECL void * -upcall_dynastack_alloc_2(size_t sz, type_desc *ty) { +upcall_s_dynastack_alloc_2(s_dynastack_alloc_2_args *args) { + size_t sz = args->sz; + type_desc *ty = args->ty; return sz ? rust_scheduler::get_task()->dynastack.alloc(sz, ty) : NULL; } +struct s_dynastack_free_args { + void *ptr; +}; + /** Frees space in the dynamic stack. */ extern "C" CDECL void -upcall_dynastack_free(void *ptr) { - return rust_scheduler::get_task()->dynastack.free(ptr); -} - -extern "C" void record_sp(void *limit); - -/** - * Switch to the C stack and call the given function, passing a single pointer - * argument. - */ -extern "C" CDECL void -upcall_call_shim_on_c_stack(void *args, void *fn_ptr) { - rust_task *task = rust_scheduler::get_task(); - - // FIXME (1226) - The shim functions generated by rustc contain the - // morestack prologue, so we need to let them know they have enough - // stack. - record_sp(0); - - rust_scheduler *sched = task->sched; - try { - sched->c_context.call_shim_on_c_stack(args, fn_ptr); - } catch (...) { - task = rust_scheduler::get_task(); - task->record_stack_limit(); - throw; - } - task = rust_scheduler::get_task(); - task->record_stack_limit(); +upcall_s_dynastack_free(s_dynastack_free_args *args) { + return rust_scheduler::get_task()->dynastack.free(args->ptr); } struct rust_new_stack2_args { @@ -275,17 +327,134 @@ __gxx_personality_v0(int version, _Unwind_Exception *ue_header, _Unwind_Context *context); +struct s_rust_personality_args { + int version; + _Unwind_Action actions; + uint64_t exception_class; + _Unwind_Exception *ue_header; + _Unwind_Context *context; +}; + +extern "C" _Unwind_Reason_Code +upcall_s_rust_personality(s_rust_personality_args *args) { + return __gxx_personality_v0(args->version, + args->actions, + args->exception_class, + args->ue_header, + args->context); +} + +// ______________________________________________________________________________ +// Upcalls in original format: deprecated and should be removed once snapshot +// transitions them away. + +extern "C" CDECL void +upcall_fail(char const *expr, + char const *file, + size_t line) { + s_fail_args args = {expr,file,line}; + upcall_s_fail(&args); +} + +extern "C" CDECL uintptr_t +upcall_malloc(size_t nbytes, type_desc *td) { + s_malloc_args args = {nbytes, td}; + return upcall_s_malloc(&args); +} + +/** + * Called whenever an object's ref count drops to zero. + */ +extern "C" CDECL void +upcall_free(void* ptr, uintptr_t is_gc) { + s_free_args args = {ptr, is_gc}; + upcall_s_free(&args); +} + +extern "C" CDECL uintptr_t +upcall_shared_malloc(size_t nbytes, type_desc *td) { + s_shared_malloc_args args = {nbytes, td}; + return upcall_s_shared_malloc(&args); +} + +/** + * Called whenever an object's ref count drops to zero. + */ +extern "C" CDECL void +upcall_shared_free(void* ptr) { + s_shared_free_args args = {ptr}; + upcall_s_shared_free(&args); +} + +extern "C" CDECL type_desc * +upcall_get_type_desc(void *curr_crate, // ignored, legacy compat. + size_t size, + size_t align, + size_t n_descs, + type_desc const **descs, + uintptr_t n_obj_params) { + s_get_type_desc_args args = {size,align,n_descs,descs,n_obj_params}; + return upcall_s_get_type_desc(&args); +} + +extern "C" CDECL void +upcall_vec_grow(rust_vec** vp, size_t new_sz) { + s_vec_grow_args args = {vp, new_sz}; + upcall_s_vec_grow(&args); +} + +extern "C" CDECL void +upcall_vec_push(rust_vec** vp, type_desc* elt_ty, void* elt) { + s_vec_push_args args = {vp, elt_ty, elt}; + upcall_s_vec_push(&args); +} + +/** + * Returns a token that can be used to deallocate all of the allocated space + * space in the dynamic stack. + */ +extern "C" CDECL void * +upcall_dynastack_mark() { + return upcall_s_dynastack_mark(); +} + +/** + * Allocates space in the dynamic stack and returns it. + * + * FIXME: Deprecated since dynamic stacks need to be self-describing for GC. + */ +extern "C" CDECL void * +upcall_dynastack_alloc(size_t sz) { + s_dynastack_alloc_args args = {sz}; + return upcall_s_dynastack_alloc(&args); +} + +/** + * Allocates space associated with a type descriptor in the dynamic stack and + * returns it. + */ +extern "C" CDECL void * +upcall_dynastack_alloc_2(size_t sz, type_desc *ty) { + s_dynastack_alloc_2_args args = {sz, ty}; + return upcall_s_dynastack_alloc_2(&args); +} + +/** Frees space in the dynamic stack. */ +extern "C" CDECL void +upcall_dynastack_free(void *ptr) { + s_dynastack_free_args args = {ptr}; + return upcall_s_dynastack_free(&args); +} + extern "C" _Unwind_Reason_Code upcall_rust_personality(int version, _Unwind_Action actions, uint64_t exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context) { - return __gxx_personality_v0(version, - actions, - exception_class, - ue_header, - context); + s_rust_personality_args args = {version, actions, exception_class, ue_header, + context}; + return upcall_s_rust_personality(&args); } // @@ -295,6 +464,5 @@ upcall_rust_personality(int version, // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix -// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; // End: // From c11d0b0aa0343fbc6ddf8114ce96904c9870de8a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Dec 2011 20:55:03 -0800 Subject: [PATCH 08/15] rt: Move upcall_cmp_type/upcall_log_type to rust_upcall.cpp --- src/rt/rust_shape.cpp | 8 ++++---- src/rt/rust_upcall.cpp | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/rt/rust_shape.cpp b/src/rt/rust_shape.cpp index 326e4e2a5140..3593d0ff335f 100644 --- a/src/rt/rust_shape.cpp +++ b/src/rt/rust_shape.cpp @@ -530,9 +530,9 @@ log::walk_res(const rust_fn *dtor, unsigned n_params, } // end namespace shape extern "C" void -upcall_cmp_type(int8_t *result, const type_desc *tydesc, - const type_desc **subtydescs, uint8_t *data_0, - uint8_t *data_1, uint8_t cmp_type) { +shape_cmp_type(int8_t *result, const type_desc *tydesc, + const type_desc **subtydescs, uint8_t *data_0, + uint8_t *data_1, uint8_t cmp_type) { rust_task *task = rust_scheduler::get_task(); shape::arena arena; @@ -553,7 +553,7 @@ upcall_cmp_type(int8_t *result, const type_desc *tydesc, } extern "C" void -upcall_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level) { +shape_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level) { rust_task *task = rust_scheduler::get_task(); if (task->sched->log_lvl < level) return; // TODO: Don't evaluate at all? diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 40cb35f0149d..c971119342c2 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -457,6 +457,26 @@ upcall_rust_personality(int version, return upcall_s_rust_personality(&args); } +extern "C" void +shape_cmp_type(int8_t *result, const type_desc *tydesc, + const type_desc **subtydescs, uint8_t *data_0, + uint8_t *data_1, uint8_t cmp_type); + +extern "C" void +upcall_cmp_type(int8_t *result, const type_desc *tydesc, + const type_desc **subtydescs, uint8_t *data_0, + uint8_t *data_1, uint8_t cmp_type) { + shape_cmp_type(result, tydesc, subtydescs, data_0, data_1, cmp_type); +} + +extern "C" void +shape_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level); + +extern "C" void +upcall_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level) { + shape_log_type(tydesc, data, level); +} + // // Local Variables: // mode: C++ From 00636e3155647f843fb1f8e8c981429feb8dd7f2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Dec 2011 21:14:00 -0800 Subject: [PATCH 09/15] rt: Convert log_type and cmp_type upcalls to shim form --- src/rt/rust_upcall.cpp | 49 +++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index c971119342c2..22dc18982d53 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -344,6 +344,41 @@ upcall_s_rust_personality(s_rust_personality_args *args) { args->context); } +extern "C" void +shape_cmp_type(int8_t *result, const type_desc *tydesc, + const type_desc **subtydescs, uint8_t *data_0, + uint8_t *data_1, uint8_t cmp_type); + +struct s_cmp_type_args { + int8_t *result; + const type_desc *tydesc; + const type_desc **subtydescs; + uint8_t *data_0; + uint8_t *data_1; + uint8_t cmp_type; +}; + +extern "C" void +upcall_s_cmp_type(s_cmp_type_args *args) { + shape_cmp_type(args->result, args->tydesc, args->subtydescs, + args->data_0, args->data_1, args->cmp_type); +} + +extern "C" void +shape_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level); + +struct s_log_type_args { + const type_desc *tydesc; + uint8_t *data; + uint32_t level; +}; + +extern "C" void +upcall_s_log_type(s_log_type_args *args) { + shape_log_type(args->tydesc, args->data, args->level); +} + + // ______________________________________________________________________________ // Upcalls in original format: deprecated and should be removed once snapshot // transitions them away. @@ -457,24 +492,18 @@ upcall_rust_personality(int version, return upcall_s_rust_personality(&args); } -extern "C" void -shape_cmp_type(int8_t *result, const type_desc *tydesc, - const type_desc **subtydescs, uint8_t *data_0, - uint8_t *data_1, uint8_t cmp_type); - extern "C" void upcall_cmp_type(int8_t *result, const type_desc *tydesc, const type_desc **subtydescs, uint8_t *data_0, uint8_t *data_1, uint8_t cmp_type) { - shape_cmp_type(result, tydesc, subtydescs, data_0, data_1, cmp_type); + s_cmp_type_args args = {result, tydesc, subtydescs, data_0, data_1, cmp_type}; + upcall_s_cmp_type(&args); } -extern "C" void -shape_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level); - extern "C" void upcall_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level) { - shape_log_type(tydesc, data, level); + s_log_type_args args = {tydesc, data, level}; + upcall_s_log_type(&args); } // From 3d7b89bc4dc63632ee0003869811933ddc1962e9 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Dec 2011 21:19:59 -0800 Subject: [PATCH 10/15] rt: Reorganize rust_upcall.cpp a bit --- src/rt/rust_upcall.cpp | 68 ++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 22dc18982d53..e4b646e39ffa 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -288,38 +288,6 @@ upcall_s_dynastack_free(s_dynastack_free_args *args) { return rust_scheduler::get_task()->dynastack.free(args->ptr); } -struct rust_new_stack2_args { - void *new_stack; - size_t stk_sz; - void *args_addr; - size_t args_sz; -}; - -// A new stack function suitable for calling through -// upcall_call_shim_on_c_stack -extern "C" CDECL void -upcall_new_stack(struct rust_new_stack2_args *args) { - rust_task *task = rust_scheduler::get_task(); - args->new_stack = task->new_stack(args->stk_sz, - args->args_addr, - args->args_sz); -} - -extern "C" CDECL void -upcall_del_stack() { - rust_task *task = rust_scheduler::get_task(); - task->del_stack(); -} - -// Landing pads need to call this to insert the -// correct limit into TLS. -// NB: This must be called on the Rust stack -extern "C" CDECL void -upcall_reset_stack_limit() { - rust_task *task = rust_scheduler::get_task(); - task->reset_stack_limit(); -} - extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, @@ -506,6 +474,42 @@ upcall_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level) { upcall_s_log_type(&args); } +struct rust_new_stack2_args { + void *new_stack; + size_t stk_sz; + void *args_addr; + size_t args_sz; +}; + +// A new stack function suitable for calling through +// upcall_call_shim_on_c_stack +// FIXME: Convert this to the same arrangement as +// the other upcalls, simplify __morestack +extern "C" CDECL void +upcall_new_stack(struct rust_new_stack2_args *args) { + rust_task *task = rust_scheduler::get_task(); + args->new_stack = task->new_stack(args->stk_sz, + args->args_addr, + args->args_sz); +} + +// FIXME: As above +extern "C" CDECL void +upcall_del_stack() { + rust_task *task = rust_scheduler::get_task(); + task->del_stack(); +} + +// Landing pads need to call this to insert the +// correct limit into TLS. +// NB: This must run on the Rust stack because it +// needs to acquire the value of the stack pointer +extern "C" CDECL void +upcall_reset_stack_limit() { + rust_task *task = rust_scheduler::get_task(); + task->reset_stack_limit(); +} + // // Local Variables: // mode: C++ From 5d1a1dc4203f8ae77e2e9c5cba393887f0b7d762 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Dec 2011 17:03:54 -0800 Subject: [PATCH 11/15] rt: Rename stk_seg.limit to stk_seg.end rust_task is using the word limit it two ways, so one has to change. --- src/rt/rust_scheduler.cpp | 1 - src/rt/rust_task.cpp | 14 +++++++------- src/rt/rust_task.h | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/rt/rust_scheduler.cpp b/src/rt/rust_scheduler.cpp index 42b2e490404a..601a7c3f0ef9 100644 --- a/src/rt/rust_scheduler.cpp +++ b/src/rt/rust_scheduler.cpp @@ -286,7 +286,6 @@ rust_scheduler::start_main_loop() { scheduled_task->state->name); place_task_in_tls(scheduled_task); - //pthread_setspecific(89, (void *)scheduled_task->stk->limit); interrupt_flag = 0; diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 888c9ac701ae..0f97a0a6853e 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -51,8 +51,8 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t minsz) LOGPTR(task->sched, "new stk", (uintptr_t)stk); memset(stk, 0, sizeof(stk_seg)); stk->next = task->stk; - stk->limit = (uintptr_t) &stk->data[minsz + RED_ZONE_SIZE]; - LOGPTR(task->sched, "stk limit", stk->limit); + stk->end = (uintptr_t) &stk->data[minsz + RED_ZONE_SIZE]; + LOGPTR(task->sched, "stk end", stk->end); stk->valgrind_id = VALGRIND_STACK_REGISTER(&stk->data[0], &stk->data[minsz + RED_ZONE_SIZE]); @@ -106,7 +106,7 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state, user.notify_enabled = 0; stk = new_stk(sched, this, 0); - user.rust_sp = stk->limit; + user.rust_sp = stk->end; if (supervisor) { supervisor->ref(); } @@ -582,7 +582,7 @@ rust_task::new_stack(size_t stk_sz, void *args_addr, size_t args_sz) { stk_seg *stk_seg = new_stk(sched, this, stk_sz + args_sz); - uint8_t *new_sp = (uint8_t*)stk_seg->limit; + uint8_t *new_sp = (uint8_t*)stk_seg->end; size_t sizeof_retaddr = sizeof(void*); // Make enough room on the new stack to hold the old stack pointer // in addition to the function arguments @@ -608,7 +608,7 @@ rust_task::record_stack_limit() { // account for those 256 bytes. const unsigned LIMIT_OFFSET = 256; A(sched, - (uintptr_t)stk->limit - RED_ZONE_SIZE + (uintptr_t)stk->end - RED_ZONE_SIZE - (uintptr_t)stk->data >= LIMIT_OFFSET, "Stack size must be greater than LIMIT_OFFSET"); record_sp(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE); @@ -627,9 +627,9 @@ rust_task::reset_stack_limit() { uintptr_t sp = get_sp(); // Not positive these bounds for sp are correct. // I think that the first possible value for esp on a new - // stack is stk->limit, which points one word in front of + // stack is stk->end, which points one word in front of // the first work to be pushed onto a new stack. - while (sp <= (uintptr_t)stk->data || stk->limit < sp) { + while (sp <= (uintptr_t)stk->data || stk->end < sp) { del_stk(this, stk); A(sched, stk != NULL, "Failed to find the current stack"); } diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 474728015101..3d5cbff99103 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -25,7 +25,7 @@ struct rust_box; struct stk_seg { stk_seg *next; - uintptr_t limit; + uintptr_t end; unsigned int valgrind_id; #ifndef _LP64 uint32_t pad; From 9656ceac60258c4189c31b402def67039ae17822 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 6 Dec 2011 17:19:24 -0800 Subject: [PATCH 12/15] rt: Put 16 guard bytes at the end of the stack --- src/rt/rust_task.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 0f97a0a6853e..bdc2f7ff7ce5 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -14,15 +14,22 @@ #include "globals.h" +// Each stack gets some guard bytes that valgrind will verify we don't touch +#ifndef NVALGRIND +#define STACK_NOACCESS_SIZE 16 +#else +#define STACK_NOACCESS_SIZE 0 +#endif + // The amount of extra space at the end of each stack segment, available // to the rt, compiler and dynamic linker for running small functions // FIXME: We want this to be 128 but need to slim the red zone calls down #ifdef __i386__ -#define RED_ZONE_SIZE 65536 +#define RED_ZONE_SIZE (65536 + STACK_NOACCESS_SIZE) #endif #ifdef __x86_64__ -#define RED_ZONE_SIZE 65536 +#define RED_ZONE_SIZE (65536 + STACK_NOACCESS_SIZE) #endif // Stack size @@ -56,6 +63,9 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t minsz) stk->valgrind_id = VALGRIND_STACK_REGISTER(&stk->data[0], &stk->data[minsz + RED_ZONE_SIZE]); +#ifndef NVALGRIND + VALGRIND_MAKE_MEM_NOACCESS(stk->data, STACK_NOACCESS_SIZE); +#endif task->stk = stk; return stk; } @@ -67,6 +77,9 @@ del_stk(rust_task *task, stk_seg *stk) task->stk = stk->next; +#ifndef NVALGRIND + VALGRIND_MAKE_MEM_DEFINED(stk->data, STACK_NOACCESS_SIZE); +#endif VALGRIND_STACK_DEREGISTER(stk->valgrind_id); LOGPTR(task->sched, "freeing stk segment", (uintptr_t)stk); task->free(stk); From d28e0c0c0ae329705a063a025b853b292ff033a7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 7 Dec 2011 14:09:45 +0100 Subject: [PATCH 13/15] Make typestate properly descend pattern guards Closes #1265 --- src/comp/middle/tstate/pre_post_conditions.rs | 4 ++++ src/comp/middle/tstate/states.rs | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index d0ac63704d78..d8e57c909866 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -452,6 +452,10 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) { expr_alt(ex, alts) { find_pre_post_expr(fcx, ex); fn do_an_alt(fcx: fn_ctxt, an_alt: arm) -> pre_and_post { + alt an_alt.guard { + some(e) { find_pre_post_expr(fcx, e); } + _ {} + } find_pre_post_block(fcx, an_alt.body); ret block_pp(fcx.ccx, an_alt.body); } diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index ed84520a6b9c..aa7977d142d3 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -530,6 +530,12 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool { if vec::len(alts) > 0u { a_post = false_postcond(num_constrs); for an_alt: arm in alts { + alt an_alt.guard { + some(e) { + changed |= find_pre_post_state_expr(fcx, e_post, e); + } + _ {} + } changed |= find_pre_post_state_block(fcx, e_post, an_alt.body); intersect(a_post, block_poststate(fcx.ccx, an_alt.body)); From 03a6e542126b755a9cd2f4f56144107ba0f4d1cd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 7 Dec 2011 15:28:57 +0100 Subject: [PATCH 14/15] Disallow binding by-mut-ref and by-move arguments Fix bug in bound by-copy arguments. Closes #1261 --- src/comp/middle/mut.rs | 25 +++++++++++++++++++++++++ src/comp/middle/trans.rs | 6 ++++++ src/libstd/task.rs | 2 +- src/test/bench/task-perf-word-count.rs | 18 +++++++++--------- src/test/stdtest/treemap.rs | 4 ++-- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/comp/middle/mut.rs b/src/comp/middle/mut.rs index 12598f3729bf..63dadd347e16 100644 --- a/src/comp/middle/mut.rs +++ b/src/comp/middle/mut.rs @@ -150,6 +150,7 @@ fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) { fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) { alt ex.node { expr_call(f, args, _) { check_call(cx, f, args); } + expr_bind(f, args) { check_bind(cx, f, args); } expr_swap(lhs, rhs) { check_lval(cx, lhs, msg_assign); check_lval(cx, rhs, msg_assign); @@ -230,6 +231,30 @@ fn check_call(cx: @ctx, f: @expr, args: [@expr]) { } } +fn check_bind(cx: @ctx, f: @expr, args: [option::t<@expr>]) { + let arg_ts = ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)); + let i = 0u; + for arg in args { + alt arg { + some(expr) { + alt (alt arg_ts[i].mode { + by_mut_ref. { some("by mutable reference") } + by_move. { some("by move") } + _ { none } + }) { + some(name) { + cx.tcx.sess.span_err( + expr.span, "can not bind an argument passed " + name); + } + none. {} + } + } + _ {} + } + i += 1u; + } +} + fn is_immutable_def(def: def) -> option::t { alt def { def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) | diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 693c8ae79e82..107c53cfac37 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3462,6 +3462,12 @@ fn trans_bind_thunk(cx: @local_ctxt, sp: span, incoming_fty: ty::t, bcx = bound_arg.bcx; let val = bound_arg.val; if out_arg.mode == ast::by_val { val = Load(bcx, val); } + if out_arg.mode == ast::by_copy { + let {bcx: cx, val: alloc} = alloc_ty(bcx, out_arg.ty); + bcx = memmove_ty(cx, alloc, val, out_arg.ty); + bcx = take_ty(bcx, alloc, out_arg.ty); + val = alloc; + } // If the type is parameterized, then we need to cast the // type we actually have to the parameterized out type. if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) { diff --git a/src/libstd/task.rs b/src/libstd/task.rs index a8765407f3af..3e396d3ac63c 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -288,7 +288,7 @@ fn spawn_inner(-data: T, f: fn(T), notify: option>) -> task unsafe { - fn wrapper(-data: *u8, f: fn(T)) unsafe { + fn wrapper(data: *u8, f: fn(T)) unsafe { let data: ~T = unsafe::reinterpret_cast(data); f(*data); } diff --git a/src/test/bench/task-perf-word-count.rs b/src/test/bench/task-perf-word-count.rs index 2d4e14af0586..d03097136335 100644 --- a/src/test/bench/task-perf-word-count.rs +++ b/src/test/bench/task-perf-word-count.rs @@ -112,12 +112,12 @@ fn reduce_task(args: (str, chan>)) { send(out, chan(p)); - let ref_count = 0; - let is_done = false; + let state = @{mutable ref_count: 0, mutable is_done: false}; - fn get(p: port, &ref_count: int, &is_done: bool) -> - option { - while !is_done || ref_count > 0 { + fn get(p: port, state: @{mutable ref_count: int, + mutable is_done: bool}) + -> option { + while !state.is_done || state.ref_count > 0 { alt recv(p) { emit_val(v) { // log_err #fmt("received %d", v); @@ -125,16 +125,16 @@ fn get(p: port, &ref_count: int, &is_done: bool) -> } done. { // log_err "all done"; - is_done = true; + state.is_done = true; } - ref. { ref_count += 1; } - release. { ref_count -= 1; } + ref. { state.ref_count += 1; } + release. { state.ref_count -= 1; } } } ret none; } - reduce(key, bind get(p, ref_count, is_done)); + reduce(key, bind get(p, state)); } fn map_reduce(-inputs: [str]) { diff --git a/src/test/stdtest/treemap.rs b/src/test/stdtest/treemap.rs index 1701be37901d..2fba1ebb1961 100644 --- a/src/test/stdtest/treemap.rs +++ b/src/test/stdtest/treemap.rs @@ -39,8 +39,8 @@ fn traverse_in_order() { insert(m, 2, ()); insert(m, 1, ()); - let n = 0; - fn t(&n: int, &&k: int, &&_v: ()) { assert (n == k); n += 1; } + let n = @mutable 0; + fn t(n: @mutable int, &&k: int, &&_v: ()) { assert (*n == k); *n += 1; } traverse(m, bind t(n, _, _)); } From 6c95e400d82699887b66f5de0fef2bb5e1f8cc32 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 7 Dec 2011 07:21:07 -0800 Subject: [PATCH 15/15] repair more hash functions --- src/comp/middle/ty.rs | 30 +++++++++++++++--------------- src/comp/syntax/ast_util.rs | 2 +- src/libstd/str.rs | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index b5b5559f4aa1..022b249674b9 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -1299,23 +1299,23 @@ fn type_autoderef(cx: ctxt, t: ty::t) -> ty::t { fn hash_type_structure(st: sty) -> uint { fn hash_uint(id: uint, n: uint) -> uint { let h = id; - h += h << 5u + n; + h += (h << 5u) + n; ret h; } fn hash_def(id: uint, did: ast::def_id) -> uint { let h = id; - h += h << 5u + (did.crate as uint); - h += h << 5u + (did.node as uint); + h += (h << 5u) + (did.crate as uint); + h += (h << 5u) + (did.node as uint); ret h; } fn hash_subty(id: uint, subty: t) -> uint { let h = id; - h += h << 5u + hash_ty(subty); + h += (h << 5u) + hash_ty(subty); ret h; } fn hash_type_constr(id: uint, c: @type_constr) -> uint { let h = id; - h += h << 5u + hash_def(h, c.node.id); + h += (h << 5u) + hash_def(h, c.node.id); ret hash_type_constr_args(h, c.node.args); } fn hash_type_constr_args(id: uint, args: [@ty_constr_arg]) -> uint { @@ -1338,8 +1338,8 @@ fn hash_type_constr_args(id: uint, args: [@ty_constr_arg]) -> uint { fn hash_fn(id: uint, args: [arg], rty: t) -> uint { let h = id; - for a: arg in args { h += h << 5u + hash_ty(a.ty); } - h += h << 5u + hash_ty(rty); + for a: arg in args { h += (h << 5u) + hash_ty(a.ty); } + h += (h << 5u) + hash_ty(rty); ret h; } alt st { @@ -1366,19 +1366,19 @@ fn hash_fn(id: uint, args: [arg], rty: t) -> uint { ty_str. { ret 17u; } ty_tag(did, tys) { let h = hash_def(18u, did); - for typ: t in tys { h += h << 5u + hash_ty(typ); } + for typ: t in tys { h += (h << 5u) + hash_ty(typ); } ret h; } ty_box(mt) { ret hash_subty(19u, mt.ty); } ty_vec(mt) { ret hash_subty(21u, mt.ty); } ty_rec(fields) { let h = 26u; - for f: field in fields { h += h << 5u + hash_ty(f.mt.ty); } + for f: field in fields { h += (h << 5u) + hash_ty(f.mt.ty); } ret h; } ty_tup(ts) { let h = 25u; - for tt in ts { h += h << 5u + hash_ty(tt); } + for tt in ts { h += (h << 5u) + hash_ty(tt); } ret h; } @@ -1389,7 +1389,7 @@ fn hash_fn(id: uint, args: [arg], rty: t) -> uint { ty_native_fn(args, rty) { ret hash_fn(28u, args, rty); } ty_obj(methods) { let h = 29u; - for m: method in methods { h += h << 5u + str::hash(m.ident); } + for m: method in methods { h += (h << 5u) + str::hash(m.ident); } ret h; } ty_var(v) { ret hash_uint(30u, v as uint); } @@ -1400,15 +1400,15 @@ fn hash_fn(id: uint, args: [arg], rty: t) -> uint { ty_ptr(mt) { ret hash_subty(35u, mt.ty); } ty_res(did, sub, tps) { let h = hash_subty(hash_def(18u, did), sub); - for tp: t in tps { h += h << 5u + hash_ty(tp); } + for tp: t in tps { h += (h << 5u) + hash_ty(tp); } ret h; } ty_constr(t, cs) { let h = 36u; - for c: @type_constr in cs { h += h << 5u + hash_type_constr(h, c); } + for c: @type_constr in cs { h += (h << 5u) + hash_type_constr(h, c); } ret h; } - ty_uniq(mt) { let h = 37u; h += h << 5u + hash_ty(mt.ty); ret h; } + ty_uniq(mt) { let h = 37u; h += (h << 5u) + hash_ty(mt.ty); ret h; } } } @@ -1416,7 +1416,7 @@ fn hash_type_info(st: sty, cname_opt: option::t) -> uint { let h = hash_type_structure(st); alt cname_opt { none. {/* no-op */ } - some(s) { h += h << 5u + str::hash(s); } + some(s) { h += (h << 5u) + str::hash(s); } } ret h; } diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs index f39b5865c251..60b3f2b6fa40 100644 --- a/src/comp/syntax/ast_util.rs +++ b/src/comp/syntax/ast_util.rs @@ -199,7 +199,7 @@ fn hash_ty(&&t: @ty) -> uint { } fn hash_def_id(&&id: def_id) -> uint { - id.crate as uint << 16u + (id.node as uint) + (id.crate as uint << 16u) + (id.node as uint) } fn eq_def_id(&&a: def_id, &&b: def_id) -> bool { diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 2bae8d699a5c..521dc33758e9 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -324,7 +324,7 @@ fn char_range_at(s: str, i: uint) -> {ch: char, next: uint} { // Clunky way to get the right bits from the first byte. Uses two shifts, // the first to clip off the marker bits at the left of the byte, and then // a second (as uint) to get it to the right position. - val += (b0 << (w + 1u as u8) as uint) << (w - 1u) * 6u - w - 1u; + val += (b0 << (w + 1u as u8) as uint) << ((w - 1u) * 6u - w - 1u); ret {ch: val as char, next: i}; }