aboutsummaryrefslogtreecommitdiff
path: root/src/rt
diff options
context:
space:
mode:
authorRoy Frostig <[email protected]>2010-09-03 16:18:32 -0700
committerRoy Frostig <[email protected]>2010-09-03 16:18:32 -0700
commit4e355aebf7c0987c3d6f66ca0013e7023aa501dd (patch)
treea1d1490532468b04d76f06a0e3351f869427de48 /src/rt
parentAssert to insure that the worst-case glue-call arg count is not exceeded unle... (diff)
downloadrust-4e355aebf7c0987c3d6f66ca0013e7023aa501dd.tar.xz
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')
-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 114e2251..954e7a13 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;