rt: Use obstacks in lieu of dynamically-sized frames
This commit is contained in:
parent
3ab21e5ee0
commit
cc5fcfce89
@ -466,17 +466,20 @@ fn alloca(cx: &@block_ctxt, t: TypeRef) -> ValueRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn array_alloca(cx: &@block_ctxt, t: TypeRef, n: ValueRef) -> ValueRef {
|
fn array_alloca(cx: &@block_ctxt, t: TypeRef, n: ValueRef) -> ValueRef {
|
||||||
|
let bcx = cx;
|
||||||
let builder = new_builder(cx.fcx.lldynamicallocas);
|
let builder = new_builder(cx.fcx.lldynamicallocas);
|
||||||
alt bcx_fcx(cx).llobstacktoken {
|
let lltaskptr = bcx_fcx(bcx).lltaskptr;
|
||||||
none. {
|
|
||||||
let dynastack_mark = bcx_ccx(cx).upcalls.dynastack_mark;
|
let dynastack_alloc = bcx_ccx(bcx).upcalls.dynastack_alloc;
|
||||||
let lltaskptr = bcx_fcx(cx).lltaskptr;
|
let llsz = builder.Mul(C_uint(llsize_of_real(bcx_ccx(bcx), t)), n);
|
||||||
bcx_fcx(cx).llobstacktoken =
|
let llresult = builder.Call(dynastack_alloc, ~[lltaskptr, llsz]);
|
||||||
some(builder.Call(dynastack_mark, ~[lltaskptr]));
|
ret builder.PointerCast(llresult, T_ptr(t));
|
||||||
}
|
}
|
||||||
some(_) { /* no-op */ }
|
|
||||||
}
|
fn mk_obstack_token(ccx: &@crate_ctxt, lldynamicallocas: BasicBlockRef,
|
||||||
ret builder.ArrayAlloca(t, n);
|
lltaskptr: ValueRef) -> ValueRef {
|
||||||
|
let builder = new_builder(lldynamicallocas);
|
||||||
|
ret builder.Call(ccx.upcalls.dynastack_mark, ~[lltaskptr]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4407,6 +4410,8 @@ fn trans_bind_thunk(cx: &@local_ctxt, sp: &span, incoming_fty: &ty::t,
|
|||||||
lltargetfn = bcx.build.PointerCast(lltargetfn, T_ptr(T_ptr(lltargetty)));
|
lltargetfn = bcx.build.PointerCast(lltargetfn, T_ptr(T_ptr(lltargetty)));
|
||||||
lltargetfn = bcx.build.Load(lltargetfn);
|
lltargetfn = bcx.build.Load(lltargetfn);
|
||||||
llvm::LLVMSetTailCall(bcx.build.FastCall(lltargetfn, llargs), 1);
|
llvm::LLVMSetTailCall(bcx.build.FastCall(lltargetfn, llargs), 1);
|
||||||
|
|
||||||
|
bcx = trans_fn_cleanups(bcx); // TODO: Might break tail call.
|
||||||
bcx.build.RetVoid();
|
bcx.build.RetVoid();
|
||||||
finish_fn(fcx, lltop);
|
finish_fn(fcx, lltop);
|
||||||
ret {val: llthunk, ty: llthunk_ty};
|
ret {val: llthunk, ty: llthunk_ty};
|
||||||
@ -5611,14 +5616,8 @@ fn trans_block_cleanups(cx: &@block_ctxt, cleanup_cx: &@block_ctxt) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn trans_fn_cleanups(bcx: &@block_ctxt) -> @block_ctxt {
|
fn trans_fn_cleanups(bcx: &@block_ctxt) -> @block_ctxt {
|
||||||
alt bcx_fcx(bcx).llobstacktoken {
|
bcx.build.Call(bcx_ccx(bcx).upcalls.dynastack_free,
|
||||||
some(lltoken_) {
|
~[bcx_fcx(bcx).lltaskptr, bcx_fcx(bcx).llobstacktoken]);
|
||||||
let lltoken = lltoken_; // satisfy alias checker
|
|
||||||
bcx.build.Call(bcx_ccx(bcx).upcalls.dynastack_free,
|
|
||||||
~[bcx_fcx(bcx).lltaskptr, lltoken]);
|
|
||||||
}
|
|
||||||
none. { /* nothing to do */ }
|
|
||||||
}
|
|
||||||
ret bcx;
|
ret bcx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5807,6 +5806,7 @@ fn new_fn_ctxt_w_id(cx: @local_ctxt, sp: &span, llfndecl: ValueRef,
|
|||||||
let derived_tydescs =
|
let derived_tydescs =
|
||||||
map::mk_hashmap::<ty::t, derived_tydesc_info>(ty::hash_ty, ty::eq_ty);
|
map::mk_hashmap::<ty::t, derived_tydesc_info>(ty::hash_ty, ty::eq_ty);
|
||||||
let llbbs = mk_standard_basic_blocks(llfndecl);
|
let llbbs = mk_standard_basic_blocks(llfndecl);
|
||||||
|
let llobstacktoken = mk_obstack_token(cx.ccx, llbbs.da, lltaskptr);
|
||||||
ret @{llfn: llfndecl,
|
ret @{llfn: llfndecl,
|
||||||
lltaskptr: lltaskptr,
|
lltaskptr: lltaskptr,
|
||||||
llenv: llenv,
|
llenv: llenv,
|
||||||
@ -5816,7 +5816,7 @@ fn new_fn_ctxt_w_id(cx: @local_ctxt, sp: &span, llfndecl: ValueRef,
|
|||||||
mutable llderivedtydescs_first: llbbs.dt,
|
mutable llderivedtydescs_first: llbbs.dt,
|
||||||
mutable llderivedtydescs: llbbs.dt,
|
mutable llderivedtydescs: llbbs.dt,
|
||||||
mutable lldynamicallocas: llbbs.da,
|
mutable lldynamicallocas: llbbs.da,
|
||||||
mutable llobstacktoken: none::<ValueRef>,
|
mutable llobstacktoken: llobstacktoken,
|
||||||
mutable llself: none::<val_self_pair>,
|
mutable llself: none::<val_self_pair>,
|
||||||
mutable lliterbody: none::<ValueRef>,
|
mutable lliterbody: none::<ValueRef>,
|
||||||
mutable iterbodyty: none::<ty::t>,
|
mutable iterbodyty: none::<ty::t>,
|
||||||
@ -6137,6 +6137,7 @@ fn trans_res_ctor(cx: @local_ctxt, sp: &span, dtor: &ast::_fn,
|
|||||||
let flag = GEP_tup_like(bcx, tup_t, llretptr, ~[0, 0]);
|
let flag = GEP_tup_like(bcx, tup_t, llretptr, ~[0, 0]);
|
||||||
bcx = flag.bcx;
|
bcx = flag.bcx;
|
||||||
bcx.build.Store(C_int(1), flag.val);
|
bcx.build.Store(C_int(1), flag.val);
|
||||||
|
bcx = trans_fn_cleanups(bcx);
|
||||||
bcx.build.RetVoid();
|
bcx.build.RetVoid();
|
||||||
finish_fn(fcx, lltop);
|
finish_fn(fcx, lltop);
|
||||||
}
|
}
|
||||||
@ -6433,6 +6434,7 @@ fn create_main_wrapper(ccx: &@crate_ctxt, sp: &span,
|
|||||||
};
|
};
|
||||||
bcx.build.FastCall(main_llfn, args);
|
bcx.build.FastCall(main_llfn, args);
|
||||||
}
|
}
|
||||||
|
bcx = trans_fn_cleanups(bcx);
|
||||||
bcx.build.RetVoid();
|
bcx.build.RetVoid();
|
||||||
|
|
||||||
let lltop = bcx.llbb;
|
let lltop = bcx.llbb;
|
||||||
@ -6754,6 +6756,7 @@ fn decl_native_fn_and_pair(ccx: &@crate_ctxt, sp: &span, path: &[str],
|
|||||||
for d: {val: ValueRef, ty: ty::t} in drop_args {
|
for d: {val: ValueRef, ty: ty::t} in drop_args {
|
||||||
bcx = drop_ty(bcx, d.val, d.ty).bcx;
|
bcx = drop_ty(bcx, d.val, d.ty).bcx;
|
||||||
}
|
}
|
||||||
|
bcx = trans_fn_cleanups(bcx);
|
||||||
bcx.build.RetVoid();
|
bcx.build.RetVoid();
|
||||||
finish_fn(fcx, lltop);
|
finish_fn(fcx, lltop);
|
||||||
}
|
}
|
||||||
|
@ -215,8 +215,7 @@ type fn_ctxt = {
|
|||||||
mutable lldynamicallocas: BasicBlockRef,
|
mutable lldynamicallocas: BasicBlockRef,
|
||||||
|
|
||||||
// The token used to clear the dynamic allocas at the end of this frame.
|
// 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: ValueRef,
|
||||||
mutable llobstacktoken: option::t<ValueRef>,
|
|
||||||
|
|
||||||
// The 'self' object currently in use in this function, if there
|
// The 'self' object currently in use in this function, if there
|
||||||
// is one.
|
// is one.
|
||||||
|
@ -192,6 +192,8 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
|
|||||||
let p = bcx.build.PointerCast(box.box, llbox_ty);
|
let p = bcx.build.PointerCast(box.box, llbox_ty);
|
||||||
bcx.build.Store(p, pair_box);
|
bcx.build.Store(p, pair_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bcx = trans_fn_cleanups(bcx);
|
||||||
bcx.build.RetVoid();
|
bcx.build.RetVoid();
|
||||||
|
|
||||||
// Insert the mandatory first few basic blocks before lltop.
|
// Insert the mandatory first few basic blocks before lltop.
|
||||||
@ -710,6 +712,7 @@ fn process_bkwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
|
|||||||
// And, finally, call the outer method.
|
// And, finally, call the outer method.
|
||||||
bcx.build.FastCall(llouter_mthd, llouter_mthd_args);
|
bcx.build.FastCall(llouter_mthd, llouter_mthd_args);
|
||||||
|
|
||||||
|
bcx = trans_fn_cleanups(bcx);
|
||||||
bcx.build.RetVoid();
|
bcx.build.RetVoid();
|
||||||
finish_fn(fcx, lltop);
|
finish_fn(fcx, lltop);
|
||||||
|
|
||||||
@ -882,6 +885,7 @@ fn process_fwding_mthd(cx: @local_ctxt, sp: &span, m: @ty::method,
|
|||||||
// And, finally, call the original (inner) method.
|
// And, finally, call the original (inner) method.
|
||||||
bcx.build.FastCall(llorig_mthd, llorig_mthd_args);
|
bcx.build.FastCall(llorig_mthd, llorig_mthd_args);
|
||||||
|
|
||||||
|
bcx = trans_fn_cleanups(bcx);
|
||||||
bcx.build.RetVoid();
|
bcx.build.RetVoid();
|
||||||
finish_fn(fcx, lltop);
|
finish_fn(fcx, lltop);
|
||||||
|
|
||||||
|
@ -14,7 +14,12 @@
|
|||||||
#undef max
|
#undef max
|
||||||
#endif
|
#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 {
|
struct rust_obstack_chunk {
|
||||||
rust_obstack_chunk *prev;
|
rust_obstack_chunk *prev;
|
||||||
@ -32,8 +37,13 @@ struct rust_obstack_chunk {
|
|||||||
|
|
||||||
void *
|
void *
|
||||||
rust_obstack_chunk::alloc(size_t len) {
|
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.
|
return NULL; // Not enough space.
|
||||||
|
}
|
||||||
void *result = data + alen;
|
void *result = data + alen;
|
||||||
alen += len;
|
alen += len;
|
||||||
return result;
|
return result;
|
||||||
@ -42,7 +52,7 @@ rust_obstack_chunk::alloc(size_t len) {
|
|||||||
bool
|
bool
|
||||||
rust_obstack_chunk::free(void *ptr) {
|
rust_obstack_chunk::free(void *ptr) {
|
||||||
uint8_t *p = (uint8_t *)ptr;
|
uint8_t *p = (uint8_t *)ptr;
|
||||||
if (p < data || p >= data + size)
|
if (p < data || p > data + size)
|
||||||
return false;
|
return false;
|
||||||
assert(p <= data + alen);
|
assert(p <= data + alen);
|
||||||
alen = (size_t)(p - data);
|
alen = (size_t)(p - data);
|
||||||
@ -54,6 +64,7 @@ void *
|
|||||||
rust_obstack::alloc_new(size_t len) {
|
rust_obstack::alloc_new(size_t len) {
|
||||||
size_t chunk_size = std::max(len, DEFAULT_CHUNK_SIZE);
|
size_t chunk_size = std::max(len, DEFAULT_CHUNK_SIZE);
|
||||||
void *ptr = task->malloc(sizeof(chunk) + chunk_size, "obstack");
|
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);
|
chunk = new(ptr) rust_obstack_chunk(chunk, chunk_size);
|
||||||
return chunk->alloc(len);
|
return chunk->alloc(len);
|
||||||
}
|
}
|
||||||
@ -70,8 +81,12 @@ void *
|
|||||||
rust_obstack::alloc(size_t len) {
|
rust_obstack::alloc(size_t len) {
|
||||||
if (!chunk)
|
if (!chunk)
|
||||||
return alloc_new(len);
|
return alloc_new(len);
|
||||||
|
|
||||||
|
DPRINT("alloc sz %u", (uint32_t)len);
|
||||||
|
|
||||||
void *ptr = chunk->alloc(len);
|
void *ptr = chunk->alloc(len);
|
||||||
ptr = ptr ? ptr : alloc_new(len);
|
ptr = ptr ? ptr : alloc_new(len);
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,8 +95,11 @@ rust_obstack::free(void *ptr) {
|
|||||||
if (!ptr)
|
if (!ptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
DPRINT("free ptr %p\n", ptr);
|
||||||
|
|
||||||
assert(chunk);
|
assert(chunk);
|
||||||
while (!chunk->free(ptr)) {
|
while (!chunk->free(ptr)) {
|
||||||
|
DPRINT("deleting chunk at %p\n", chunk);
|
||||||
rust_obstack_chunk *prev = chunk->prev;
|
rust_obstack_chunk *prev = chunk->prev;
|
||||||
task->free(chunk);
|
task->free(chunk);
|
||||||
chunk = prev;
|
chunk = prev;
|
||||||
|
@ -64,18 +64,6 @@ const uint8_t CMP_LT = 1u;
|
|||||||
const uint8_t CMP_LE = 2u;
|
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
|
// Utility classes
|
||||||
|
|
||||||
struct size_align {
|
struct size_align {
|
||||||
@ -185,11 +173,18 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline ptr_pair
|
} // end namespace shape
|
||||||
align_to(const ptr_pair &pair, size_t n) {
|
|
||||||
return ptr_pair::make(align_to(pair.fst, n), align_to(pair.snd, n));
|
|
||||||
|
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.
|
// NB: This function does not align.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline data_pair<T>
|
inline data_pair<T>
|
||||||
|
@ -430,7 +430,7 @@ upcall_dynastack_mark(rust_task *task) {
|
|||||||
/** Allocates space in the dynamic stack and returns it. */
|
/** Allocates space in the dynamic stack and returns it. */
|
||||||
extern "C" CDECL void *
|
extern "C" CDECL void *
|
||||||
upcall_dynastack_alloc(rust_task *task, size_t sz) {
|
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. */
|
/** Frees space in the dynamic stack. */
|
||||||
|
@ -125,6 +125,16 @@ next_power_of_two(size_t s)
|
|||||||
return tmp + 1;
|
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
|
// Initialization helper for ISAAC RNG
|
||||||
|
|
||||||
template <typename sched_or_kernel>
|
template <typename sched_or_kernel>
|
||||||
|
Loading…
Reference in New Issue
Block a user