rt: Make the dynamic stack self-describing

This commit is contained in:
Patrick Walton 2011-08-31 19:19:05 -07:00
parent 729437d2c0
commit 614a930c51
7 changed files with 74 additions and 25 deletions

View File

@ -109,7 +109,8 @@ fn declare_upcalls(_tn: type_names, tydesc_type: TypeRef,
[taskptr_type, T_ptr(tydesc_type), T_ptr(T_i8()), T_i32()],
T_void()),
dynastack_mark: d(~"dynastack_mark", [], T_ptr(T_i8())),
dynastack_alloc: d(~"dynastack_alloc", [T_size_t()], T_ptr(T_i8())),
dynastack_alloc: d(~"dynastack_alloc_2",
[T_size_t(), T_ptr(tydesc_type)], T_ptr(T_i8())),
dynastack_free: d(~"dynastack_free", [T_ptr(T_i8())], T_void())};
}
//

View File

@ -471,7 +471,8 @@ fn alloca(cx: &@block_ctxt, t: TypeRef) -> ValueRef {
ret Alloca(new_raw_block_ctxt(cx.fcx, cx.fcx.llstaticallocas), t);
}
fn array_alloca(cx: &@block_ctxt, t: TypeRef, n: ValueRef) -> ValueRef {
fn dynastack_alloca(cx: &@block_ctxt, t: TypeRef, n: ValueRef, ty: ty::t)
-> ValueRef {
let bcx = cx;
let dy_cx = new_raw_block_ctxt(cx.fcx, cx.fcx.lldynamicallocas);
let lltaskptr = bcx_fcx(bcx).lltaskptr;
@ -485,7 +486,11 @@ fn array_alloca(cx: &@block_ctxt, t: TypeRef, n: ValueRef) -> ValueRef {
let dynastack_alloc = bcx_ccx(bcx).upcalls.dynastack_alloc;
let llsz = Mul(dy_cx, C_uint(llsize_of_real(bcx_ccx(bcx), t)), n);
let llresult = Call(dy_cx, dynastack_alloc, [lltaskptr, llsz]);
let ti = none;
let lltydesc = get_tydesc(cx, ty, false, tps_normal, ti).result.val;
let llresult = Call(dy_cx, dynastack_alloc, [lltaskptr, llsz, lltydesc]);
ret PointerCast(dy_cx, llresult, T_ptr(t));
}
@ -4868,8 +4873,10 @@ fn alloc_ty(cx: &@block_ctxt, t: ty::t) -> result {
let n = size_of(llderivedtydescs_block_ctxt(bcx.fcx), t);
bcx.fcx.llderivedtydescs = n.bcx.llbb;
val = array_alloca(bcx, T_i8(), n.val);
} else { val = alloca(bcx, type_of(bcx_ccx(cx), cx.sp, t)); }
val = dynastack_alloca(bcx, T_i8(), n.val, t);
} else {
val = alloca(bcx, type_of(bcx_ccx(cx), cx.sp, t));
}
// NB: since we've pushed all size calculations in this
// function up to the alloca block, we actually return the
// block passed into us unmodified; it doesn't really

View File

@ -5,7 +5,7 @@ import lib::llvm::llvm::{ValueRef, TypeRef};
import back::abi;
import trans::{call_memmove, trans_shared_malloc, llsize_of,
type_of_or_i8, incr_ptr, INIT, copy_val, load_if_immediate,
alloca, array_alloca, size_of, llderivedtydescs_block_ctxt,
alloca, size_of, llderivedtydescs_block_ctxt,
lazily_emit_tydesc_glue, get_tydesc, load_inbounds,
move_val_if_temp, trans_lval, node_id_type,
new_sub_block_ctxt, tps_normal, do_spill};

View File

@ -3,6 +3,7 @@
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <new>
#include <stdint.h>
#include "rust_internal.h"
@ -18,9 +19,20 @@
#define DPRINT(fmt,...)
//const size_t DEFAULT_CHUNK_SIZE = 4096;
const size_t DEFAULT_CHUNK_SIZE = 300000;
const size_t DEFAULT_CHUNK_SIZE = 500000;
const size_t DEFAULT_ALIGNMENT = 16;
// A single type-tagged allocation in a chunk.
struct rust_obstack_alloc {
size_t len;
const type_desc *tydesc;
uint8_t data[];
rust_obstack_alloc(size_t in_len, const type_desc *in_tydesc)
: len(in_len), tydesc(in_tydesc) {}
};
// A contiguous set of allocations.
struct rust_obstack_chunk {
rust_obstack_chunk *prev;
size_t size;
@ -31,22 +43,24 @@ struct rust_obstack_chunk {
rust_obstack_chunk(rust_obstack_chunk *in_prev, size_t in_size)
: prev(in_prev), size(in_size), alen(0) {}
void *alloc(size_t len);
void *alloc(size_t len, type_desc *tydesc);
bool free(void *ptr);
void *mark();
};
void *
rust_obstack_chunk::alloc(size_t len) {
rust_obstack_chunk::alloc(size_t len, type_desc *tydesc) {
alen = align_to(alen, DEFAULT_ALIGNMENT);
if (len > size - alen) {
if (sizeof(rust_obstack_alloc) + 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;
rust_obstack_alloc *a = new(data + alen) rust_obstack_alloc(len, tydesc);
alen += sizeof(*a) + len;
return &a->data;
}
bool
@ -59,14 +73,20 @@ rust_obstack_chunk::free(void *ptr) {
return true;
}
void *
rust_obstack_chunk::mark() {
return data + alen;
}
// Allocates the given number of bytes in a new chunk.
void *
rust_obstack::alloc_new(size_t len) {
size_t chunk_size = std::max(len, DEFAULT_CHUNK_SIZE);
rust_obstack::alloc_new(size_t len, type_desc *tydesc) {
size_t chunk_size = std::max(sizeof(rust_obstack_alloc) + 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);
return chunk->alloc(len, tydesc);
}
rust_obstack::~rust_obstack() {
@ -78,14 +98,14 @@ rust_obstack::~rust_obstack() {
}
void *
rust_obstack::alloc(size_t len) {
rust_obstack::alloc(size_t len, type_desc *tydesc) {
if (!chunk)
return alloc_new(len);
return alloc_new(len, tydesc);
DPRINT("alloc sz %u", (uint32_t)len);
void *ptr = chunk->alloc(len);
ptr = ptr ? ptr : alloc_new(len);
void *ptr = chunk->alloc(len, tydesc);
ptr = ptr ? ptr : alloc_new(len, tydesc);
return ptr;
}
@ -107,3 +127,8 @@ rust_obstack::free(void *ptr) {
}
}
void *
rust_obstack::mark() {
return chunk ? chunk->mark() : NULL;
}

View File

@ -5,20 +5,22 @@
struct rust_obstack_chunk;
struct rust_task;
struct type_desc;
class rust_obstack {
rust_obstack_chunk *chunk;
rust_task *task;
// Allocates the given number of bytes in a new chunk.
void *alloc_new(size_t len);
void *alloc_new(size_t len, type_desc *tydesc);
public:
rust_obstack(rust_task *in_task) : chunk(NULL), task(in_task) {}
~rust_obstack();
void *alloc(size_t len);
void *alloc(size_t len, type_desc *tydesc);
void free(void *ptr);
void *mark();
};
#endif

View File

@ -368,13 +368,26 @@ upcall_vec_push(rust_task* task, rust_vec** vp, type_desc* elt_ty,
*/
extern "C" CDECL void *
upcall_dynastack_mark(rust_task *task) {
return task->dynastack.alloc(0);
return task->dynastack.mark();
}
/** Allocates space in the dynamic stack and returns it. */
/**
* 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(rust_task *task, size_t sz) {
return sz ? task->dynastack.alloc(sz) : NULL;
return sz ? task->dynastack.alloc(sz, NULL) : NULL;
}
/**
* Allocates space associated with a type descriptor in the dynamic stack and
* returns it.
*/
extern "C" CDECL void *
upcall_dynastack_alloc_2(rust_task *task, size_t sz, type_desc *ty) {
return sz ? task->dynastack.alloc(sz, ty) : NULL;
}
/** Frees space in the dynamic stack. */

View File

@ -77,6 +77,7 @@ task_join
unsupervise
upcall_cmp_type
upcall_dynastack_alloc
upcall_dynastack_alloc_2
upcall_dynastack_free
upcall_dynastack_mark
upcall_exit