about summary refs log tree commit diff
path: root/src/rt/rust_upcall.cpp
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-06-14 18:32:04 -0700
committerPatrick Walton <pcwalton@mimiga.net>2011-06-14 18:32:04 -0700
commitac743cfcb022b3d0b6bb6b382eaa5b9d9d8fd98c (patch)
tree97f4ae26db7fa584bb7fdcaefe779101e2d0fc9f /src/rt/rust_upcall.cpp
parentc6be352f73927ddf44357aaf87b161b5805263c0 (diff)
parentccd1bcf7a754a5437cd108bb6bb8a32848334fe6 (diff)
downloadrust-ac743cfcb022b3d0b6bb6b382eaa5b9d9d8fd98c.tar.gz
rust-ac743cfcb022b3d0b6bb6b382eaa5b9d9d8fd98c.zip
Merge pull request #490 from msullivan/fix_vec_append
Move the implementation of vec_append from llvm assembly to a regular upcall 
Diffstat (limited to 'src/rt/rust_upcall.cpp')
-rw-r--r--src/rt/rust_upcall.cpp49
1 files changed, 48 insertions, 1 deletions
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index c58723d1b50..c3945bdd0c8 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -415,7 +415,7 @@ upcall_vec_grow(rust_task *task,
          *
          * 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
+         * type information 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.
          */
@@ -436,6 +436,53 @@ upcall_vec_grow(rust_task *task,
     return v;
 }
 
+// Copy elements from one vector to another,
+// dealing with reference counts
+static inline void
+copy_elements(rust_task *task, type_desc *elem_t,
+              void *pdst, void *psrc, size_t n)
+{
+    char *dst = (char *)pdst, *src = (char *)psrc;
+
+    // increment the refcount of each element of the vector
+    if (elem_t->take_glue) {
+        glue_fn *take_glue = elem_t->take_glue;
+        size_t elem_size = elem_t->size;
+        const type_desc **tydescs = elem_t->first_param;
+        for (char *p = src; p < src+n; p += elem_size) {
+            take_glue(NULL, task, NULL, tydescs, p);
+        }
+    }
+    memmove(dst, src, n);
+}
+
+extern "C" CDECL void
+upcall_vec_append(rust_task *task, type_desc *t, type_desc *elem_t,
+                  rust_vec **dst_ptr, rust_vec *src, bool skip_null)
+{
+    LOG_UPCALL_ENTRY(task);
+    rust_vec *dst = *dst_ptr;
+    uintptr_t need_copy;
+    size_t n_src_bytes = skip_null ? src->fill - 1 : src->fill;
+    size_t n_dst_bytes = skip_null ? dst->fill - 1 : dst->fill;
+    rust_vec *new_vec = upcall_vec_grow(task, dst, n_src_bytes,
+                                        &need_copy, t);
+
+    if (need_copy) {
+        // Copy any dst elements in, omitting null if doing str.
+        copy_elements(task, elem_t, &new_vec->data, &dst->data, n_dst_bytes);
+    }
+
+    // Copy any src elements in, carrying along null if doing str.
+    void *new_end = (void *)((char *)new_vec->data + n_dst_bytes);
+    copy_elements(task, elem_t, new_end, &src->data, src->fill);
+    new_vec->fill = n_dst_bytes + src->fill;
+
+    // Write new_vec back through the alias we were given.
+    *dst_ptr = new_vec;
+}
+
+
 extern "C" CDECL type_desc *
 upcall_get_type_desc(rust_task *task,
                      void *curr_crate, // ignored, legacy compat.