From d8c5bd61956924e041be240cff9458141ca74187 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 16 Aug 2011 19:48:47 -0700 Subject: [PATCH] rt: Implement obstacks, untested as of yet --- mk/rt.mk | 1 + src/rt/rust_obstack.cpp | 82 +++++++++++++++++++++++++++++++++++++++++ src/rt/rust_obstack.h | 24 ++++++++++++ src/rt/rust_task.cpp | 3 +- src/rt/rust_task.h | 3 ++ src/rt/rust_upcall.cpp | 22 +++++++++++ src/rt/rustrt.def.in | 3 ++ 7 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/rt/rust_obstack.cpp create mode 100644 src/rt/rust_obstack.h diff --git a/mk/rt.mk b/mk/rt.mk index 11e110666ab..6082baf01c9 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -25,6 +25,7 @@ RUNTIME_CS := rt/sync/timer.cpp \ rt/rust_srv.cpp \ rt/rust_kernel.cpp \ rt/rust_shape.cpp \ + rt/rust_obstack.cpp \ rt/memory_region.cpp \ rt/test/rust_test_harness.cpp \ rt/test/rust_test_runtime.cpp \ diff --git a/src/rt/rust_obstack.cpp b/src/rt/rust_obstack.cpp new file mode 100644 index 00000000000..342310d4b5c --- /dev/null +++ b/src/rt/rust_obstack.cpp @@ -0,0 +1,82 @@ +// Object stacks, used in lieu of dynamically-sized frames. + +#include +#include +#include +#include + +#include "rust_internal.h" +#include "rust_obstack.h" +#include "rust_task.h" + +// ISAAC, let go of max()! +#ifdef max +#undef max +#endif + +const size_t DEFAULT_CHUNK_SIZE = 4096; + +struct rust_obstack_chunk { + rust_obstack_chunk *prev; + size_t size; + size_t alen; + size_t pad; + uint8_t data[]; + + 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); + bool free(void *ptr); +}; + +void * +rust_obstack_chunk::alloc(size_t len) { + if (len > size - alen) + return NULL; // Not enough space. + void *result = data + alen; + alen += len; + return result; +} + +bool +rust_obstack_chunk::free(void *ptr) { + uint8_t *p = (uint8_t *)ptr; + if (p < data || p >= data + size) + return false; + assert(p < data + alen); + alen = (size_t)(p - data); + return true; +} + +// 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); + void *ptr = task->malloc(sizeof(chunk) + chunk_size, "obstack"); + chunk = new(ptr) rust_obstack_chunk(chunk, chunk_size); + return chunk->alloc(len); +} + +void * +rust_obstack::alloc(size_t len) { + if (!chunk) + return alloc_new(len); + void *ptr = chunk->alloc(len); + return ptr ? ptr : alloc_new(len); +} + +void +rust_obstack::free(void *ptr) { + if (!ptr) + return; + + assert(chunk); + while (!chunk->free(ptr)) { + rust_obstack_chunk *prev = chunk->prev; + task->free(chunk); + chunk = prev; + assert(chunk); + } +} + diff --git a/src/rt/rust_obstack.h b/src/rt/rust_obstack.h new file mode 100644 index 00000000000..5a80638aba7 --- /dev/null +++ b/src/rt/rust_obstack.h @@ -0,0 +1,24 @@ +// Object stacks, used in lieu of dynamically-sized frames. + +#ifndef RUST_OBSTACK_H +#define RUST_OBSTACK_H + +struct rust_obstack_chunk; +struct rust_task; + +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); + +public: + rust_obstack(rust_task *in_task) : chunk(NULL), task(in_task) {} + + void *alloc(size_t len); + void free(void *ptr); +}; + +#endif + diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index c877d5e9941..b8269554237 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -75,7 +75,8 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state, local_region(&sched->srv->local_region), _on_wakeup(NULL), failed(false), - propagate_failure(true) + propagate_failure(true), + dynastack(this) { LOGPTR(sched, "new task", (uintptr_t)this); DLOG(sched, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this); diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index a688c405e60..f1513ada616 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -8,6 +8,7 @@ #include "util/array_list.h" #include "context.h" +#include "rust_obstack.h" struct stk_seg { unsigned int valgrind_id; @@ -122,6 +123,8 @@ rust_task : public kernel_owned, rust_cond hash_map port_table; + rust_obstack dynastack; + // Only a pointer to 'name' is kept, so it must live as long as this task. rust_task(rust_scheduler *sched, rust_task_list *state, diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 5fd0127c7e7..d04de59a4df 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -417,6 +417,28 @@ upcall_ivec_spill_shared(rust_task *task, v->alloc = new_alloc; v->payload.ptr = heap_part; } + +/** + * Returns a token that can be used to deallocate all of the allocated space + * space in the dynamic stack. + */ +extern "C" CDECL void * +upcall_dynastack_mark(rust_task *task) { + return task->dynastack.alloc(0); +} + +/** 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); +} + +/** Frees space in the dynamic stack. */ +extern "C" CDECL void +upcall_dynastack_free(rust_task *task, void *ptr) { + return task->dynastack.free(ptr); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index c200fc9d3cb..0d05d7ffa43 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -83,6 +83,9 @@ task_yield task_join unsupervise upcall_cmp_type +upcall_dynastack_alloc +upcall_dynastack_free +upcall_dynastack_mark upcall_exit upcall_fail upcall_free