about summary refs log tree commit diff
path: root/src/rt
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2010-06-28 18:53:16 -0700
committerGraydon Hoare <graydon@mozilla.com>2010-06-28 18:53:43 -0700
commit5abc483d9a96b20f51df2c19d14d07165ba1f57a (patch)
treec2ee4c6d4be802c0f1959d2c68828cc5a4654392 /src/rt
parenta27cbd4ee8d1ea1061d726dcd8939f54edd257e4 (diff)
downloadrust-5abc483d9a96b20f51df2c19d14d07165ba1f57a.tar.gz
rust-5abc483d9a96b20f51df2c19d14d07165ba1f57a.zip
Move more of the GC logic into the runtime.
Diffstat (limited to 'src/rt')
-rw-r--r--src/rt/rust_internal.h23
-rw-r--r--src/rt/rust_log.cpp1
-rw-r--r--src/rt/rust_log.h1
-rw-r--r--src/rt/rust_task.cpp78
-rw-r--r--src/rt/rust_upcall.cpp39
5 files changed, 131 insertions, 11 deletions
diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h
index c9a28946e7b..fafc1924a55 100644
--- a/src/rt/rust_internal.h
+++ b/src/rt/rust_internal.h
@@ -595,6 +595,19 @@ struct frame_glue_fns {
     uintptr_t reloc_glue_off;
 };
 
+struct gc_alloc {
+    gc_alloc *prev;
+    gc_alloc *next;
+    uintptr_t ctrl_word;
+    uint8_t data[];
+    bool mark() {
+        if (ctrl_word & 1)
+            return false;
+        ctrl_word |= 1;
+        return true;
+    }
+};
+
 struct
 rust_task : public rc_base<rust_task>,
             public dom_owned<rust_task>,
@@ -604,7 +617,7 @@ rust_task : public rc_base<rust_task>,
     stk_seg *stk;
     uintptr_t runtime_sp;      // Runtime sp while task running.
     uintptr_t rust_sp;         // Saved sp when not running.
-    uintptr_t gc_alloc_chain;  // Linked list of GC allocations.
+    gc_alloc *gc_alloc_chain;  // Linked list of GC allocations.
     rust_dom *dom;
     rust_crate_cache *cache;
 
@@ -614,6 +627,8 @@ rust_task : public rc_base<rust_task>,
     uintptr_t* dptr;           // Rendezvous pointer for send/recv.
     rust_task *spawner;        // Parent-link.
     size_t idx;
+    size_t gc_alloc_thresh;
+    size_t gc_alloc_accum;
 
     // Wait queue for tasks waiting for this task.
     rust_wait_queue waiting_tasks;
@@ -633,6 +648,12 @@ rust_task : public rc_base<rust_task>,
     bool blocked_on(rust_cond *cond);
     bool dead();
 
+    void link_gc(gc_alloc *gcm);
+    void unlink_gc(gc_alloc *gcm);
+    void *malloc(size_t sz, type_desc *td=0);
+    void *realloc(void *data, size_t sz, bool gc_mem=false);
+    void free(void *p, bool gc_mem=false);
+
     const char *state_str();
     void transition(ptr_vec<rust_task> *svec, ptr_vec<rust_task> *dvec);
 
diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp
index 102a26237f7..5cdf315c7c6 100644
--- a/src/rt/rust_log.cpp
+++ b/src/rt/rust_log.cpp
@@ -21,6 +21,7 @@ static uint32_t read_type_bit_mask() {
         bits |= strstr(env_str, "dwarf") ? rust_log::DWARF : 0;
         bits |= strstr(env_str, "cache") ? rust_log::CACHE : 0;
         bits |= strstr(env_str, "timer") ? rust_log::TIMER : 0;
+        bits |= strstr(env_str, "gc") ? rust_log::GC : 0;
         bits |= strstr(env_str, "all") ? rust_log::ALL : 0;
     }
     return bits;
diff --git a/src/rt/rust_log.h b/src/rt/rust_log.h
index b0c5fbeca77..bd32c1550e4 100644
--- a/src/rt/rust_log.h
+++ b/src/rt/rust_log.h
@@ -44,6 +44,7 @@ public:
         CACHE = 0x100,
         UPCALL = 0x200,
         TIMER = 0x400,
+        GC = 0x800,
         ALL = 0xffffffff
     };
 
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 3f85f51ac7b..bf92ba90ec4 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -408,6 +408,84 @@ rust_task::dead()
 }
 
 void
+rust_task::link_gc(gc_alloc *gcm) {
+    I(dom, gcm->prev == NULL);
+    I(dom, gcm->next == NULL);
+    gcm->prev = NULL;
+    gcm->next = gc_alloc_chain;
+}
+
+void
+rust_task::unlink_gc(gc_alloc *gcm) {
+    if (gcm->prev)
+        gcm->prev->next = gcm->next;
+    if (gcm->next)
+        gcm->next->prev = gcm->prev;
+    gcm->prev = NULL;
+    gcm->next = NULL;
+}
+
+void *
+rust_task::malloc(size_t sz, type_desc *td)
+{
+    if (td) {
+        sz += sizeof(gc_alloc);
+    }
+    void *mem = dom->malloc(sz);
+    if (!mem)
+        return mem;
+    if (td) {
+        gc_alloc *gcm = (gc_alloc*) mem;
+        dom->log(rust_log::TASK|rust_log::MEM|rust_log::GC,
+                 "task 0x%" PRIxPTR " allocated %d GC bytes = 0x%" PRIxPTR,
+                 (uintptr_t)this, sz, gcm);
+        memset((void*) gcm, 0, sizeof(gc_alloc));
+        link_gc(gcm);
+        gcm->ctrl_word = (uintptr_t)td;
+        gc_alloc_accum += sz;
+        mem = (void*) &(gcm->data);
+    }
+    return mem;;
+}
+
+void *
+rust_task::realloc(void *data, size_t sz, bool is_gc)
+{
+    if (is_gc) {
+        gc_alloc *gcm = (gc_alloc*)(((char *)data) - sizeof(gc_alloc));
+        unlink_gc(gcm);
+        sz += sizeof(gc_alloc);
+        gcm = (gc_alloc*) dom->realloc((void*)gcm, sz);
+        dom->log(rust_log::TASK|rust_log::MEM|rust_log::GC,
+                 "task 0x%" PRIxPTR " reallocated %d GC bytes = 0x%" PRIxPTR,
+                 (uintptr_t)this, sz, gcm);
+        if (!gcm)
+            return gcm;
+        link_gc(gcm);
+        data = (void*) &(gcm->data);
+    } else {
+        data = dom->realloc(data, sz);
+    }
+    return data;
+}
+
+void
+rust_task::free(void *p, bool is_gc)
+{
+    if (is_gc) {
+        gc_alloc *gcm = (gc_alloc*)(((char *)p) - sizeof(gc_alloc));
+        unlink_gc(gcm);
+        dom->log(rust_log::TASK|rust_log::MEM|rust_log::GC,
+                 "task 0x%" PRIxPTR " freeing GC memory = 0x%" PRIxPTR,
+                 (uintptr_t)this, gcm);
+        dom->free(gcm);
+    } else {
+        dom->free(p);
+    }
+}
+
+
+void
 rust_task::transition(ptr_vec<rust_task> *src, ptr_vec<rust_task> *dst)
 {
     I(dom, state == src);
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 3a17ea1ce9a..ffe775325fc 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -324,19 +324,20 @@ upcall_exit(rust_task *task)
 }
 
 extern "C" CDECL uintptr_t
-upcall_malloc(rust_task *task, size_t nbytes)
+upcall_malloc(rust_task *task, size_t nbytes, type_desc *td)
 {
     LOG_UPCALL_ENTRY(task);
 
-    void *p = task->dom->malloc(nbytes);
+    void *p = task->malloc(nbytes, td);
     task->dom->log(rust_log::UPCALL|rust_log::MEM,
-                   "upcall malloc(%u) = 0x%" PRIxPTR,
-                   nbytes, (uintptr_t)p);
+                   "upcall malloc(%u) = 0x%" PRIxPTR
+                   " with gc-chain head = 0x%" PRIxPTR,
+                   nbytes, (uintptr_t)p, task->gc_alloc_chain);
     return (uintptr_t) p;
 }
 
 extern "C" CDECL void
-upcall_free(rust_task *task, void* ptr)
+upcall_free(rust_task *task, void* ptr, uintptr_t is_gc)
 {
     LOG_UPCALL_ENTRY(task);
 
@@ -344,7 +345,24 @@ upcall_free(rust_task *task, void* ptr)
     dom->log(rust_log::UPCALL|rust_log::MEM,
              "upcall free(0x%" PRIxPTR ")",
              (uintptr_t)ptr);
-    dom->free(ptr);
+    task->free(ptr, (bool) is_gc);
+}
+
+extern "C" CDECL uintptr_t
+upcall_mark(rust_task *task, void* ptr)
+{
+    LOG_UPCALL_ENTRY(task);
+
+    rust_dom *dom = task->dom;
+    if (ptr) {
+        gc_alloc *gcm = (gc_alloc*) (((char*)ptr) - sizeof(gc_alloc));
+        uintptr_t marked = (uintptr_t) gcm->mark();
+        dom->log(rust_log::UPCALL|rust_log::MEM|rust_log::GC,
+                 "upcall mark(0x%" PRIxPTR ") = %" PRIdPTR,
+                 (uintptr_t)gcm, marked);
+        return marked;
+    }
+    return 0;
 }
 
 extern "C" CDECL rust_str *
@@ -368,14 +386,15 @@ upcall_new_str(rust_task *task, char const *s, size_t fill)
 }
 
 extern "C" CDECL rust_vec *
-upcall_new_vec(rust_task *task, size_t fill)
+upcall_new_vec(rust_task *task, size_t fill, type_desc *td)
 {
     LOG_UPCALL_ENTRY(task);
     rust_dom *dom = task->dom;
     dom->log(rust_log::UPCALL|rust_log::MEM,
-             "upcall new_vec(%" PRIdPTR ")", fill);
+             "upcall new_vec(%" PRIdPTR ")",
+             fill);
     size_t alloc = next_power_of_two(sizeof(rust_vec) + fill);
-    void *mem = dom->malloc(alloc);
+    void *mem = task->malloc(alloc, td);
     if (!mem) {
         task->fail(3);
         return NULL;
@@ -389,7 +408,7 @@ upcall_new_vec(rust_task *task, size_t fill)
 
 
 extern "C" CDECL rust_str *
-upcall_vec_grow(rust_task *task, rust_vec *v, size_t n_bytes)
+upcall_vec_grow(rust_task *task, rust_vec *v, size_t n_bytes, uintptr_t is_gc)
 {
     LOG_UPCALL_ENTRY(task);
     rust_dom *dom = task->dom;