diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 8ecac617e195..9d797db2ee9b 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -466,17 +466,28 @@ fn alloca(cx: &@block_ctxt, t: TypeRef) -> ValueRef { } fn array_alloca(cx: &@block_ctxt, t: TypeRef, n: ValueRef) -> ValueRef { + let bcx = cx; let builder = new_builder(cx.fcx.lldynamicallocas); + let lltaskptr = bcx_fcx(bcx).lltaskptr; alt bcx_fcx(cx).llobstacktoken { none. { - let dynastack_mark = bcx_ccx(cx).upcalls.dynastack_mark; - let lltaskptr = bcx_fcx(cx).lltaskptr; bcx_fcx(cx).llobstacktoken = - some(builder.Call(dynastack_mark, ~[lltaskptr])); + some(mk_obstack_token(bcx_ccx(cx), cx.fcx.lldynamicallocas, + lltaskptr)); } some(_) { /* no-op */ } } - ret builder.ArrayAlloca(t, n); + + let dynastack_alloc = bcx_ccx(bcx).upcalls.dynastack_alloc; + let llsz = builder.Mul(C_uint(llsize_of_real(bcx_ccx(bcx), t)), n); + let llresult = builder.Call(dynastack_alloc, ~[lltaskptr, llsz]); + ret builder.PointerCast(llresult, T_ptr(t)); +} + +fn mk_obstack_token(ccx: &@crate_ctxt, lldynamicallocas: BasicBlockRef, + lltaskptr: ValueRef) -> ValueRef { + let builder = new_builder(lldynamicallocas); + ret builder.Call(ccx.upcalls.dynastack_mark, ~[lltaskptr]); } diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 2285aeefc8f1..d37e01f573c6 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -217,7 +217,6 @@ type fn_ctxt = { mutable llreturn: BasicBlockRef, // The token used to clear the dynamic allocas at the end of this frame. - // Will be |none| if there are no dynamic allocas. mutable llobstacktoken: option::t, // The 'self' object currently in use in this function, if there diff --git a/src/rt/rust_obstack.cpp b/src/rt/rust_obstack.cpp index 5ec996f4e32f..f76a80aada98 100644 --- a/src/rt/rust_obstack.cpp +++ b/src/rt/rust_obstack.cpp @@ -14,7 +14,12 @@ #undef max #endif -const size_t DEFAULT_CHUNK_SIZE = 4096; +//#define DPRINT(fmt,...) fprintf(stderr, fmt, ##__VA_ARGS__) +#define DPRINT(fmt,...) + +//const size_t DEFAULT_CHUNK_SIZE = 4096; +const size_t DEFAULT_CHUNK_SIZE = 300000; +const size_t DEFAULT_ALIGNMENT = 16; struct rust_obstack_chunk { rust_obstack_chunk *prev; @@ -32,8 +37,13 @@ struct rust_obstack_chunk { void * rust_obstack_chunk::alloc(size_t len) { - if (len > size - alen) + alen = align_to(alen, DEFAULT_ALIGNMENT); + + if (len > size - alen) { + DPRINT("Not enough space, len=%lu!\n", len); + assert(0); return NULL; // Not enough space. + } void *result = data + alen; alen += len; return result; @@ -42,7 +52,7 @@ rust_obstack_chunk::alloc(size_t len) { bool rust_obstack_chunk::free(void *ptr) { uint8_t *p = (uint8_t *)ptr; - if (p < data || p >= data + size) + if (p < data || p > data + size) return false; assert(p <= data + alen); alen = (size_t)(p - data); @@ -54,6 +64,7 @@ void * rust_obstack::alloc_new(size_t len) { size_t chunk_size = std::max(len, DEFAULT_CHUNK_SIZE); void *ptr = task->malloc(sizeof(chunk) + chunk_size, "obstack"); + DPRINT("making new chunk at %p, len %lu\n", ptr, chunk_size); chunk = new(ptr) rust_obstack_chunk(chunk, chunk_size); return chunk->alloc(len); } @@ -70,8 +81,12 @@ void * rust_obstack::alloc(size_t len) { if (!chunk) return alloc_new(len); + + DPRINT("alloc sz %u", (uint32_t)len); + void *ptr = chunk->alloc(len); ptr = ptr ? ptr : alloc_new(len); + return ptr; } @@ -80,8 +95,11 @@ rust_obstack::free(void *ptr) { if (!ptr) return; + DPRINT("free ptr %p\n", ptr); + assert(chunk); while (!chunk->free(ptr)) { + DPRINT("deleting chunk at %p\n", chunk); rust_obstack_chunk *prev = chunk->prev; task->free(chunk); chunk = prev; diff --git a/src/rt/rust_shape.cpp b/src/rt/rust_shape.cpp index c23d3aaa858b..e5b96e7e91f7 100644 --- a/src/rt/rust_shape.cpp +++ b/src/rt/rust_shape.cpp @@ -64,18 +64,6 @@ const uint8_t CMP_LT = 1u; const uint8_t CMP_LE = 2u; -// Utility functions - -// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power -// of two. -template -static inline T -align_to(T size, size_t alignment) { - assert(alignment); - T x = (T)(((uintptr_t)size + alignment - 1) & ~(alignment - 1)); - return x; -} - // Utility classes struct size_align { @@ -185,11 +173,18 @@ public: } }; -inline ptr_pair -align_to(const ptr_pair &pair, size_t n) { - return ptr_pair::make(align_to(pair.fst, n), align_to(pair.snd, n)); +} // end namespace shape + + +inline shape::ptr_pair +align_to(const shape::ptr_pair &pair, size_t n) { + return shape::ptr_pair::make(align_to(pair.fst, n), + align_to(pair.snd, n)); } + +namespace shape { + // NB: This function does not align. template inline data_pair diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index d04de59a4dfa..ac99f501f25a 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -430,7 +430,7 @@ upcall_dynastack_mark(rust_task *task) { /** Allocates space in the dynamic stack and returns it. */ extern "C" CDECL void * upcall_dynastack_alloc(rust_task *task, size_t sz) { - return task->dynastack.alloc(sz); + return sz ? task->dynastack.alloc(sz) : NULL; } /** Frees space in the dynamic stack. */ diff --git a/src/rt/rust_util.h b/src/rt/rust_util.h index 6e6f364e3a63..401c39413b65 100644 --- a/src/rt/rust_util.h +++ b/src/rt/rust_util.h @@ -125,6 +125,16 @@ next_power_of_two(size_t s) return tmp + 1; } +// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power +// of two. +template +static inline T +align_to(T size, size_t alignment) { + assert(alignment); + T x = (T)(((uintptr_t)size + alignment - 1) & ~(alignment - 1)); + return x; +} + // Initialization helper for ISAAC RNG template