about summary refs log tree commit diff
path: root/src/rt/rust_upcall.cpp
diff options
context:
space:
mode:
authorRoy Frostig <rfrostig@mozilla.com>2010-09-03 16:18:32 -0700
committerRoy Frostig <rfrostig@mozilla.com>2010-09-03 16:18:32 -0700
commit4e355aebf7c0987c3d6f66ca0013e7023aa501dd (patch)
treea1d1490532468b04d76f06a0e3351f869427de48 /src/rt/rust_upcall.cpp
parent1eb2a8b10be2063637e510794ed6bbc49693b5b8 (diff)
downloadrust-4e355aebf7c0987c3d6f66ca0013e7023aa501dd.tar.gz
rust-4e355aebf7c0987c3d6f66ca0013e7023aa501dd.zip
When vec growth results in a newly allocated (extended) buffer, copy existing elements over via element-wise copy, not flat memcpy. Introduce new vec growth glue to achieve this.
Diffstat (limited to 'src/rt/rust_upcall.cpp')
-rw-r--r--src/rt/rust_upcall.cpp35
1 files changed, 26 insertions, 9 deletions
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 114e2251694..954e7a13ded 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -384,18 +384,23 @@ upcall_new_vec(rust_task *task, size_t fill, type_desc *td) {
     return v;
 }
 
-extern "C" CDECL rust_str *
+extern "C" CDECL rust_vec *
 upcall_vec_grow(rust_task *task,
                 rust_vec *v,
                 size_t n_bytes,
-                uintptr_t is_gc) {
+                uintptr_t *need_copy)
+{
     LOG_UPCALL_ENTRY(task);
     rust_dom *dom = task->dom;
-    task->log(rust_log::UPCALL|rust_log::MEM,
-             "upcall vec_grow(0x%" PRIxPTR ", %" PRIdPTR
-             "), alloc=%" PRIdPTR ", fill=%" PRIdPTR,
-             v, n_bytes, v->alloc, v->fill);
+    task->log(rust_log::UPCALL | rust_log::MEM,
+              "upcall vec_grow(0x%" PRIxPTR ", %" PRIdPTR
+              "), alloc=%" PRIdPTR ", fill=%" PRIdPTR
+              ", need_copy=0x%" PRIxPTR,
+              v, n_bytes, v->alloc, v->fill, need_copy);
+
+    *need_copy = 0;
     size_t alloc = next_power_of_two(sizeof(rust_vec) + v->fill + n_bytes);
+
     if (v->ref_count == 1) {
 
         // Fastest path: already large enough.
@@ -414,7 +419,19 @@ upcall_vec_grow(rust_task *task,
         v->alloc = alloc;
 
     } else {
-        // Slowest path: make a new vec.
+        /**
+         * Slowest path: make a new vec.
+         *
+         * 1. Allocate a new rust_vec with desired additional space.
+         * 2. Down-ref the shared rust_vec, point to the new one instead.
+         * 3. Copy existing elements into the new rust_vec.
+         *
+         * Step 3 is a bit tricky.  We don't know how to properly copy the
+         * elements in the runtime (all we have are bits in a buffer; no
+         * type infromation and no copy glue).  What we do instead is set the
+         * need_copy outparam flag to indicate to our caller (vec-copy glue)
+         * that we need the copies performed for us.
+         */
         task->log(rust_log::UPCALL | rust_log::MEM, "new vec path");
         void *mem = dom->malloc(alloc);
         if (!mem) {
@@ -422,8 +439,8 @@ upcall_vec_grow(rust_task *task,
             return NULL;
         }
         v->deref();
-        v = new (mem) rust_vec(dom, alloc, v->fill,
-                               v->fill ? &v->data[0] : NULL);
+        v = new (mem) rust_vec(dom, alloc, 0, NULL);
+        *need_copy = 1;
     }
     I(dom, sizeof(rust_vec) + v->fill <= v->alloc);
     return v;