rustc: Use obstacks in lieu of dynamically-allocated frames only when the frame is actually dynamically-sized
This commit is contained in:
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<ValueRef>,
|
||||
|
||||
// The 'self' object currently in use in this function, if there
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<typename T>
|
||||
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<typename T>
|
||||
inline data_pair<T>
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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<typename T>
|
||||
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 <typename sched_or_kernel>
|
||||
|
||||
Reference in New Issue
Block a user