From 614a930c51d8e8f66e6893261616a449d9ab0754 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 31 Aug 2011 19:19:05 -0700 Subject: [PATCH] rt: Make the dynamic stack self-describing --- src/comp/back/upcall.rs | 3 +- src/comp/middle/trans.rs | 15 +++++++--- src/comp/middle/trans_ivec.rs | 2 +- src/rt/rust_obstack.cpp | 53 ++++++++++++++++++++++++++--------- src/rt/rust_obstack.h | 6 ++-- src/rt/rust_upcall.cpp | 19 +++++++++++-- src/rt/rustrt.def.in | 1 + 7 files changed, 74 insertions(+), 25 deletions(-) diff --git a/src/comp/back/upcall.rs b/src/comp/back/upcall.rs index 8f0cb959b3d..4d14145d8f7 100644 --- a/src/comp/back/upcall.rs +++ b/src/comp/back/upcall.rs @@ -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())}; } // diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index c71e04ae747..bf548e5ea73 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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 diff --git a/src/comp/middle/trans_ivec.rs b/src/comp/middle/trans_ivec.rs index 6c891f6a6a5..9b269d042c0 100644 --- a/src/comp/middle/trans_ivec.rs +++ b/src/comp/middle/trans_ivec.rs @@ -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}; diff --git a/src/rt/rust_obstack.cpp b/src/rt/rust_obstack.cpp index f76a80aada9..d703cfca63c 100644 --- a/src/rt/rust_obstack.cpp +++ b/src/rt/rust_obstack.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #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; +} + diff --git a/src/rt/rust_obstack.h b/src/rt/rust_obstack.h index 595be6fa3a5..6483a5f8d11 100644 --- a/src/rt/rust_obstack.h +++ b/src/rt/rust_obstack.h @@ -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 diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 77c7cf1a113..98dd9136d9d 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -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. */ diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 2f3f25eb64f..3bfad837555 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -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