diff --git a/src/rt/rust_box.h b/src/rt/rust_box.h index e69de29bb2d..52d1046895c 100644 --- a/src/rt/rust_box.h +++ b/src/rt/rust_box.h @@ -0,0 +1,18 @@ +/* Rust box representation. */ + +#ifndef RUST_BOX_H +#define RUST_BOX_H + +#include "rust_internal.h" +#include + +struct rust_box { + RUST_REFCOUNTED(rust_box) + type_desc *tydesc; + rust_box *gc_next; + rust_box *gc_prev; + uint8_t data[0]; +}; + +#endif + diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index d1a9b66f9e5..afc6f682ceb 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -10,6 +10,8 @@ #include "context.h" #include "rust_obstack.h" +struct rust_box; + struct stk_seg { unsigned int valgrind_id; uintptr_t limit; @@ -57,7 +59,7 @@ rust_task : public kernel_owned, rust_cond context ctx; stk_seg *stk; uintptr_t runtime_sp; // Runtime sp while task running. - void *gc_alloc_chain; // Linked list of GC allocations. + rust_box *gc_alloc_chain; // Linked list of GC allocations. rust_scheduler *sched; rust_crate_cache *cache; diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 778e90df162..0150cc31e48 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -1,3 +1,4 @@ +#include "rust_box.h" #include "rust_gc.h" #include "rust_internal.h" #include "rust_unwind.h" @@ -76,6 +77,25 @@ upcall_malloc(rust_task *task, size_t nbytes, type_desc *td) { return (uintptr_t) p; } +extern "C" CDECL rust_box * +upcall_malloc_box(rust_task *task, size_t nbytes, type_desc *td) { + LOG_UPCALL_ENTRY(task); + + gc::maybe_gc(task); + + rust_box *box = reinterpret_cast + (task->malloc(nbytes + sizeof(rust_box), "tdesc", td)); + box->ref_count = 1; + box->tydesc = td; + + box->gc_prev = NULL; + if ((box->gc_next = task->gc_alloc_chain) != NULL) + box->gc_next->gc_prev = box; + task->gc_alloc_chain = box; + + return box; +} + /** * Called whenever an object's ref count drops to zero. */ @@ -90,6 +110,24 @@ upcall_free(rust_task *task, void* ptr, uintptr_t is_gc) { task->free(ptr, (bool) is_gc); } +extern "C" CDECL void +upcall_free_box(rust_task *task, rust_box *box) { + LOG_UPCALL_ENTRY(task); + + assert(!box->ref_count && "Box reference count is nonzero on free!"); + + if (box->gc_prev) + box->gc_prev->gc_next = box->gc_next; + else + task->gc_alloc_chain = box->gc_next; + if (box->gc_next) + box->gc_next->gc_prev = box->gc_prev; + + box->tydesc->drop_glue(NULL, task, (void *)box->tydesc, + box->tydesc->first_param, box->data); + task->free(box, false); +} + extern "C" CDECL uintptr_t upcall_shared_malloc(rust_task *task, size_t nbytes, type_desc *td) { LOG_UPCALL_ENTRY(task);