about summary refs log tree commit diff
path: root/src/rt
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-08-25 10:18:02 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-08-29 09:07:53 +0200
commitc9c5ee252a8523778377f2832765442e611e85a4 (patch)
tree85c0837af34b2431fc17da0a166254144aaa99c7 /src/rt
parent855e0a471365c7c61a139e2437215028bd231af5 (diff)
downloadrust-c9c5ee252a8523778377f2832765442e611e85a4.tar.gz
rust-c9c5ee252a8523778377f2832765442e611e85a4.zip
Implement non-internal ivecs
Vectors are now similar to our old, pre-internal vectors, except that
they are uniquely owned, not refcounted.

Their name should probably change too, then. I've renamed them to vec
in the runtime, will do so throughout the compiler later.
Diffstat (limited to 'src/rt')
-rw-r--r--src/rt/intrinsics/intrinsics.cpp13
-rw-r--r--src/rt/intrinsics/intrinsics.ll.in27
-rw-r--r--src/rt/main.ll.in10
-rw-r--r--src/rt/rust.cpp20
-rw-r--r--src/rt/rust_builtin.cpp222
-rw-r--r--src/rt/rust_shape.cpp15
-rw-r--r--src/rt/rust_shape.h85
-rw-r--r--src/rt/rust_upcall.cpp84
-rw-r--r--src/rt/rust_util.h24
-rw-r--r--src/rt/rust_uv.cpp21
-rw-r--r--src/rt/rustrt.def.in17
11 files changed, 132 insertions, 406 deletions
diff --git a/src/rt/intrinsics/intrinsics.cpp b/src/rt/intrinsics/intrinsics.cpp
index a9f90326007..bbe0fc811dd 100644
--- a/src/rt/intrinsics/intrinsics.cpp
+++ b/src/rt/intrinsics/intrinsics.cpp
@@ -9,17 +9,10 @@ extern "C" CDECL void
 upcall_fail(rust_task *task, char const *expr, char const *file, size_t line);
 
 extern "C" void
-rust_intrinsic_ivec_len(rust_task *task, size_t *retptr, type_desc *ty,
-                        rust_ivec *v)
+rust_intrinsic_vec_len(rust_task *task, size_t *retptr, type_desc *ty,
+                       rust_vec **vp)
 {
-    size_t fill;
-    if (v->fill)
-        fill = v->fill;
-    else if (v->payload.ptr)
-        fill = v->payload.ptr->fill;
-    else
-        fill = 0;
-    *retptr = fill / ty->size;
+    *retptr = (*vp)->fill / ty->size;
 }
 
 extern "C" void
diff --git a/src/rt/intrinsics/intrinsics.ll.in b/src/rt/intrinsics/intrinsics.ll.in
index 17937329df5..872cec7fa21 100644
--- a/src/rt/intrinsics/intrinsics.ll.in
+++ b/src/rt/intrinsics/intrinsics.ll.in
@@ -40,9 +40,7 @@ target triple = "@CFG_LLVM_TRIPLE@"
 %struct.registers_t = type { i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i16, i16, i32, i32 }
 %"class.rust_task::wakeup_callback" = type { i32 (...)** }
 %struct.rc_base.5 = type { i32 }
-%struct.rust_ivec = type { i32, i32, %union.rust_ivec_payload }
-%union.rust_ivec_payload = type { %struct.rust_ivec_heap* }
-%struct.rust_ivec_heap = type { i32, [0 x i8] }
+%struct.rust_vec = type { i32, i32, [ 0 x i8 ] }
 %class.rust_port = type { i32, %class.rust_kernel*, %struct.rust_task*, i32, %class.ptr_vec, %class.ptr_vec.7, %class.rust_chan*, %class.lock_and_signal }
 %class.ptr_vec = type { %struct.rust_task*, i32, i32, %struct.rust_token** }
 %struct.rust_token = type opaque
@@ -53,29 +51,14 @@ target triple = "@CFG_LLVM_TRIPLE@"
 @.str = private unnamed_addr constant [42 x i8] c"attempt to cast values of differing sizes\00", align 1
 @.str1 = private unnamed_addr constant [15 x i8] c"intrinsics.cpp\00", align 1
 
-define linkonce_odr void @rust_intrinsic_ivec_len(%struct.rust_task* nocapture %task, i32* nocapture %retptr, %struct.type_desc* nocapture %ty, %struct.rust_ivec* nocapture %v) nounwind {
+define linkonce_odr void @rust_intrinsic_vec_len(%struct.rust_task* nocapture %task, i32* nocapture %retptr, %struct.type_desc* nocapture %ty, %struct.rust_vec** nocapture %v) nounwind {
 entry:
-  %fill1 = getelementptr inbounds %struct.rust_ivec* %v, i32 0, i32 0
+  %ptr1 = load %struct.rust_vec** %v, align 4, !tbaa !0
+  %fill1 = getelementptr inbounds %struct.rust_vec* %ptr1, i32 0, i32 0
   %tmp2 = load i32* %fill1, align 4, !tbaa !0
-  %tobool = icmp eq i32 %tmp2, 0
-  br i1 %tobool, label %if.else, label %if.end17
-
-if.else:                                          ; preds = %entry
-  %ptr = getelementptr inbounds %struct.rust_ivec* %v, i32 0, i32 2, i32 0
-  %tmp7 = load %struct.rust_ivec_heap** %ptr, align 4, !tbaa !3
-  %tobool8 = icmp eq %struct.rust_ivec_heap* %tmp7, null
-  br i1 %tobool8, label %if.end17, label %if.then9
-
-if.then9:                                         ; preds = %if.else
-  %fill14 = getelementptr inbounds %struct.rust_ivec_heap* %tmp7, i32 0, i32 0
-  %tmp15 = load i32* %fill14, align 4, !tbaa !0
-  br label %if.end17
-
-if.end17:                                         ; preds = %if.else, %entry, %if.then9
-  %fill.0 = phi i32 [ %tmp15, %if.then9 ], [ %tmp2, %entry ], [ 0, %if.else ]
   %size = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
   %tmp20 = load i32* %size, align 4, !tbaa !0
-  %div = udiv i32 %fill.0, %tmp20
+  %div = udiv i32 %tmp2, %tmp20
   store i32 %div, i32* %retptr, align 4, !tbaa !0
   ret void
 }
diff --git a/src/rt/main.ll.in b/src/rt/main.ll.in
index 391f4d8daaf..6df51e67503 100644
--- a/src/rt/main.ll.in
+++ b/src/rt/main.ll.in
@@ -10,21 +10,21 @@
 
 %task = type { i32, i32, i32, i32, i32, i32, i32, i32 }
 
-%ivec = type { i32, i32, [4 x { i32, i32, i32, i32, [0 x i8] }*] }
+%vec = type { i32, i32, [0 x i8] }
 
 @_rust_crate_map_toplevel = external global %0
 
 declare i32 @rust_start(i32, i32, i32, i32)
 
-declare external fastcc void @_rust_main(i1* nocapture, %task*, %2* nocapture, %ivec*)
+declare external fastcc void @_rust_main(i1* nocapture, %task*, %2* nocapture, %vec*)
 
-define void @_rust_main_wrap(i1* nocapture, %task *, %2* nocapture, %ivec *)
+define void @_rust_main_wrap(i1* nocapture, %task *, %2* nocapture, %vec *)
 {
-  tail call fastcc void @_rust_main(i1* %0, %task *%1, %2* nocapture %2, %ivec* %3)
+  tail call fastcc void @_rust_main(i1* %0, %task *%1, %2* nocapture %2, %vec* %3)
   ret void
 }
 
 define i32 @"MAIN"(i32, i32) {
-  %3 = tail call i32 @rust_start(i32 ptrtoint (void (i1*, %task*, %2*, %ivec*)* @_rust_main_wrap to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32))
+  %3 = tail call i32 @rust_start(i32 ptrtoint (void (i1*, %task*, %2*, %vec*)* @_rust_main_wrap to i32), i32 %0, i32 %1, i32 ptrtoint (%0* @_rust_crate_map_toplevel to i32))
   ret i32 %3
 }
diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp
index a158be04e57..b5a462154ed 100644
--- a/src/rt/rust.cpp
+++ b/src/rt/rust.cpp
@@ -10,7 +10,7 @@ command_line_args : public kernel_owned<command_line_args>
     rust_str **strs;
 
     // [str] passed to rust_task::start.
-    rust_ivec *args;
+    rust_vec *args;
 
     command_line_args(rust_task *task,
                       int sys_argc,
@@ -51,21 +51,13 @@ command_line_args : public kernel_owned<command_line_args>
             strs[i]->ref_count++;
         }
 
-        size_t ivec_interior_sz =
-            sizeof(size_t) * 2 + sizeof(rust_str *) * 4;
-        args = (rust_ivec *)
-            kernel->malloc(ivec_interior_sz,
+        args = (rust_vec *)
+            kernel->malloc(vec_size<rust_str*>(argc),
                            "command line arg interior");
-        args->fill = 0;
-        size_t ivec_exterior_sz = sizeof(rust_str *) * argc;
-        args->alloc = ivec_exterior_sz;
-        // NB: _rust_main owns the ivec payload and will be responsible for
+        args->fill = args->alloc = sizeof(rust_str *) * argc;
+        // NB: _rust_main owns the vec and will be responsible for
         // freeing it
-        args->payload.ptr = (rust_ivec_heap *)
-            kernel->malloc(ivec_exterior_sz + sizeof(size_t),
-                           "command line arg exterior");
-        args->payload.ptr->fill = ivec_exterior_sz;
-        memcpy(&args->payload.ptr->data, strs, ivec_exterior_sz);
+        memcpy(&args->data[0], strs, args->fill);
     }
 
     ~command_line_args() {
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index 044239065e9..a8929677aff 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -206,18 +206,14 @@ str_byte_len(rust_task *task, rust_str *s)
 }
 
 extern "C" CDECL rust_str *
-str_from_ivec(rust_task *task, rust_ivec *v)
+str_from_vec(rust_task *task, rust_vec **vp)
 {
-    bool is_interior = v->fill || !v->payload.ptr;
-    uintptr_t fill = is_interior ? v->fill : v->payload.ptr->fill;
-    void *data = is_interior ? v->payload.data : v->payload.ptr->data;
-
-    rust_str *st =
-        vec_alloc_with_data(task,
-                            fill + 1,   // +1 to fit at least '\0'
-                            fill,
-                            1,
-                            fill ? data : NULL);
+    rust_vec* v = *vp;
+    rust_str *st = vec_alloc_with_data(task,
+                                       v->fill + 1, // +1 for \0
+                                       v->fill,
+                                       1,
+                                       &v->data[0]);
     if (!st) {
         task->fail();
         return NULL;
@@ -226,6 +222,33 @@ str_from_ivec(rust_task *task, rust_ivec *v)
     return st;
 }
 
+extern "C" CDECL void
+vec_reserve_shared(rust_task* task, type_desc* ty, rust_vec** vp,
+                    size_t n_elts) {
+    size_t new_sz = n_elts * ty->size;
+    if (new_sz > (*vp)->alloc) {
+        size_t new_alloc = next_power_of_two(new_sz);
+        *vp = (rust_vec*)task->kernel->realloc(*vp, new_alloc +
+                                                sizeof(rust_vec));
+        (*vp)->alloc = new_alloc;
+    }
+}
+
+/**
+ * Copies elements in an unsafe buffer to the given interior vector. The
+ * vector must have size zero.
+ */
+extern "C" CDECL rust_vec*
+vec_from_buf_shared(rust_task *task, type_desc *ty,
+                     void *ptr, size_t count) {
+    size_t fill = ty->size * count;
+    rust_vec* v = (rust_vec*)task->kernel->malloc(fill + sizeof(rust_vec),
+                                                    "vec_from_buf");
+    v->fill = v->alloc = fill;
+    memmove(&v->data[0], ptr, fill);
+    return v;
+}
+
 extern "C" CDECL rust_str *
 str_from_cstr(rust_task *task, char *sbuf)
 {
@@ -471,23 +494,19 @@ rust_list_files(rust_task *task, rust_str *path) {
       closedir(dirp);
   }
 #endif
-  size_t str_ivec_sz =
-      sizeof(size_t)            // fill
-      + sizeof(size_t)          // alloc
-      + sizeof(rust_str *) * 4; // payload
-  rust_box *box = (rust_box *)task->malloc(sizeof(rust_box) + str_ivec_sz,
-                                           "rust_box(list_files_ivec)");
+  rust_box *box =
+      (rust_box *)task->malloc(sizeof(rust_box) + sizeof(rust_vec*),
+                               "rust_box(list_files_vec)");
+  rust_vec* vec =
+      (rust_vec*)task->kernel->malloc(vec_size<rust_str*>(strings.size()),
+                                       "list_files_vec");
 
   box->ref_count = 1;
-  rust_ivec *iv = (rust_ivec *)&box->data;
-  iv->fill = 0;
-
-  size_t alloc_sz = sizeof(rust_str *) * strings.size();
-  iv->alloc = alloc_sz;
-  iv->payload.ptr = (rust_ivec_heap *)
-      task->kernel->malloc(alloc_sz + sizeof(size_t), "files ivec");
-  iv->payload.ptr->fill = alloc_sz;
-  memcpy(&iv->payload.ptr->data, strings.data(), alloc_sz);
+  rust_vec** box_content = (rust_vec**)&box->data[0];
+  *box_content = vec;
+  size_t alloc_sz = sizeof(rust_str*) * strings.size();
+  vec->fill = vec->alloc = alloc_sz;
+  memcpy(&vec->data[0], strings.data(), alloc_sz);
   return box;
 }
 
@@ -549,157 +568,6 @@ nano_time(rust_task *task, uint64_t *ns) {
     *ns = t.time_ns();
 }
 
-/**
- * Preallocates the exact number of bytes in the given interior vector.
- */
-extern "C" CDECL void
-ivec_reserve(rust_task *task, type_desc *ty, rust_ivec *v, size_t n_elems)
-{
-    size_t new_alloc = n_elems * ty->size;
-    if (new_alloc <= v->alloc)
-        return;     // Already big enough.
-
-    rust_ivec_heap *heap_part;
-    if (v->fill || !v->payload.ptr) {
-        // On stack; spill to heap.
-        heap_part = (rust_ivec_heap *)task->malloc(new_alloc +
-                                                   sizeof(size_t),
-                                                   "ivec reserve heap part");
-        heap_part->fill = v->fill;
-        memcpy(&heap_part->data, v->payload.data, v->fill);
-
-        v->fill = 0;
-        v->payload.ptr = heap_part;
-    } else {
-        // On heap; resize.
-        heap_part = (rust_ivec_heap *)
-            task->realloc(v->payload.ptr,
-                          new_alloc + sizeof(size_t));
-        v->payload.ptr = heap_part;
-    }
-
-    v->alloc = new_alloc;
-}
-
-/**
- * Preallocates the exact number of bytes in the given interior vector.
- */
-extern "C" CDECL void
-ivec_reserve_shared(rust_task *task, type_desc *ty, rust_ivec *v,
-                    size_t n_elems)
-{
-    size_t new_alloc = n_elems * ty->size;
-    if (new_alloc <= v->alloc)
-        return;     // Already big enough.
-
-    rust_ivec_heap *heap_part;
-    if (v->fill || !v->payload.ptr) {
-        // On stack; spill to heap.
-        heap_part = (rust_ivec_heap *)
-            task->kernel->malloc(new_alloc + sizeof(size_t),
-                                 "ivec reserve shared");
-        heap_part->fill = v->fill;
-        memcpy(&heap_part->data, v->payload.data, v->fill);
-
-        v->fill = 0;
-        v->payload.ptr = heap_part;
-    } else {
-        // On heap; resize.
-        heap_part = (rust_ivec_heap *)task->kernel->realloc(v->payload.ptr,
-                                                new_alloc + sizeof(size_t));
-        v->payload.ptr = heap_part;
-    }
-
-    v->alloc = new_alloc;
-}
-
-/**
- * Returns true if the given vector is on the heap and false if it's on the
- * stack.
- */
-extern "C" CDECL bool
-ivec_on_heap(rust_task *task, type_desc *ty, rust_ivec *v)
-{
-    return !v->fill && v->payload.ptr;
-}
-
-/**
- * Returns an unsafe pointer to the data part of an interior vector.
- */
-extern "C" CDECL void *
-ivec_to_ptr(rust_task *task, type_desc *ty, rust_ivec *v)
-{
-    return v->fill ? v->payload.data : v->payload.ptr->data;
-}
-
-static size_t
-get_ivec_size(rust_ivec *v)
-{
-    if (v->fill)
-        return v->fill;
-    if (v->payload.ptr)
-        return v->payload.ptr->fill;
-    return 0;
-}
-
-/**
- * Copies elements in an unsafe buffer to the given interior vector. The
- * vector must have size zero.
- */
-extern "C" CDECL void
-ivec_copy_from_buf(rust_task *task, type_desc *ty, rust_ivec *v, void *ptr,
-                   size_t count)
-{
-    size_t old_size = get_ivec_size(v);
-    if (old_size) {
-        task->fail();
-        return;
-    }
-
-    ivec_reserve(task, ty, v, count);
-
-    size_t new_size = count * ty->size;
-    if (v->fill || !v->payload.ptr) {
-        // On stack.
-        memmove(v->payload.data, ptr, new_size);
-        v->fill = new_size;
-        return;
-    }
-
-    // On heap.
-    memmove(v->payload.ptr->data, ptr, new_size);
-    v->payload.ptr->fill = new_size;
-}
-
-/**
- * Copies elements in an unsafe buffer to the given interior vector. The
- * vector must have size zero.
- */
-extern "C" CDECL void
-ivec_copy_from_buf_shared(rust_task *task, type_desc *ty, rust_ivec *v,
-                   void *ptr, size_t count)
-{
-    size_t old_size = get_ivec_size(v);
-    if (old_size) {
-        task->fail();
-        return;
-    }
-
-    ivec_reserve_shared(task, ty, v, count);
-
-    size_t new_size = count * ty->size;
-    if (v->fill || !v->payload.ptr) {
-        // On stack.
-        memmove(v->payload.data, ptr, new_size);
-        v->fill = new_size;
-        return;
-    }
-
-    // On heap.
-    memmove(v->payload.ptr->data, ptr, new_size);
-    v->payload.ptr->fill = new_size;
-}
-
 extern "C" CDECL void
 pin_task(rust_task *task) {
     task->pin();
diff --git a/src/rt/rust_shape.cpp b/src/rt/rust_shape.cpp
index f56aa0251ce..c08663bface 100644
--- a/src/rt/rust_shape.cpp
+++ b/src/rt/rust_shape.cpp
@@ -226,17 +226,6 @@ size_of::walk_struct(bool align, const uint8_t *end_sp) {
     sa = struct_sa;
 }
 
-void
-size_of::walk_ivec(bool align, bool is_pod, size_align &elem_sa) {
-    if (!elem_sa.is_set())
-        walk(align);    // Determine the size the slow way.
-    else
-        sa = elem_sa;   // Use the size hint.
-
-    sa.set(sizeof(rust_ivec) - sizeof(uintptr_t) + sa.size * 4,
-           max(sa.alignment, sizeof(uintptr_t)));
-}
-
 
 // Copy constructors
 
@@ -321,8 +310,8 @@ public:
         walk_vec(align, is_pod, get_evec_data_range(dp));
     }
 
-    void walk_ivec(bool align, bool is_pod, size_align &elem_sa) {
-        walk_vec(align, is_pod, get_ivec_data_range(dp));
+    void walk_vec(bool align, bool is_pod, uint16_t sp_size) {
+        walk_vec(align, is_pod, get_vec_data_range(dp));
     }
 
     void walk_box(bool align) {
diff --git a/src/rt/rust_shape.h b/src/rt/rust_shape.h
index eb683110180..2ce4fcb5645 100644
--- a/src/rt/rust_shape.h
+++ b/src/rt/rust_shape.h
@@ -37,7 +37,7 @@ const uint8_t SHAPE_I64 = 7u;
 const uint8_t SHAPE_F32 = 8u;
 const uint8_t SHAPE_F64 = 9u;
 const uint8_t SHAPE_EVEC = 10u;
-const uint8_t SHAPE_IVEC = 11u;
+const uint8_t SHAPE_VEC = 11u;
 const uint8_t SHAPE_TAG = 12u;
 const uint8_t SHAPE_BOX = 13u;
 const uint8_t SHAPE_STRUCT = 17u;
@@ -192,7 +192,7 @@ protected:
 
 private:
     void walk_evec(bool align);
-    void walk_ivec(bool align);
+    void walk_vec(bool align);
     void walk_tag(bool align);
     void walk_box(bool align);
     void walk_struct(bool align);
@@ -278,6 +278,7 @@ public:
 template<typename T>
 void
 ctxt<T>::walk(bool align) {
+  
     switch (*sp++) {
     case SHAPE_U8:      WALK_NUMBER(uint8_t);   break;
     case SHAPE_U16:     WALK_NUMBER(uint16_t);  break;
@@ -290,7 +291,7 @@ ctxt<T>::walk(bool align) {
     case SHAPE_F32:     WALK_NUMBER(float);     break;
     case SHAPE_F64:     WALK_NUMBER(double);    break;
     case SHAPE_EVEC:    walk_evec(align);       break;
-    case SHAPE_IVEC:    walk_ivec(align);       break;
+    case SHAPE_VEC:     walk_vec(align);        break;
     case SHAPE_TAG:     walk_tag(align);        break;
     case SHAPE_BOX:     walk_box(align);        break;
     case SHAPE_STRUCT:  walk_struct(align);     break;
@@ -347,18 +348,13 @@ ctxt<T>::walk_evec(bool align) {
 
 template<typename T>
 void
-ctxt<T>::walk_ivec(bool align) {
+ctxt<T>::walk_vec(bool align) {
     bool is_pod = *sp++;
-    size_align elem_sa = get_size_align(sp);
 
     uint16_t sp_size = get_u16_bump(sp);
     const uint8_t *end_sp = sp + sp_size;
 
-    // FIXME: Hack to work around our incorrect alignment in some cases.
-    if (elem_sa.alignment == 8)
-        elem_sa.alignment = 4;
-
-    static_cast<T *>(this)->walk_ivec(align, is_pod, elem_sa);
+    static_cast<T *>(this)->walk_vec(align, is_pod, sp_size);
 
     sp = end_sp;
 }
@@ -471,8 +467,8 @@ public:
     void walk_evec(bool align, bool is_pod, uint16_t sp_size) {
         DPRINT("evec<"); walk(align); DPRINT(">");
     }
-    void walk_ivec(bool align, bool is_pod, size_align &elem_sa) {
-        DPRINT("ivec<"); walk(align); DPRINT(">");
+    void walk_vec(bool align, bool is_pod, uint16_t sp_size) {
+        DPRINT("vec<"); walk(align); DPRINT(">");
     }
     void walk_box(bool align) {
         DPRINT("box<"); walk(align); DPRINT(">");
@@ -522,7 +518,6 @@ public:
 
     void walk_tag(bool align, tag_info &tinfo);
     void walk_struct(bool align, const uint8_t *end_sp);
-    void walk_ivec(bool align, bool is_pod, size_align &elem_sa);
 
     void walk_box(bool align)   { sa.set(sizeof(void *),   sizeof(void *)); }
     void walk_port(bool align)  { sa.set(sizeof(void *),   sizeof(void *)); }
@@ -534,6 +529,9 @@ public:
     void walk_evec(bool align, bool is_pod, uint16_t sp_size) {
         sa.set(sizeof(void *), sizeof(void *));
     }
+    void walk_vec(bool align, bool is_pod, uint16_t sp_size) {
+        sa.set(sizeof(void*), sizeof(void*));
+    }
 
     void walk_var(bool align, uint8_t param_index) {
         const type_param *param = &params[param_index];
@@ -725,9 +723,9 @@ protected:
     void walk_variant(bool align, tag_info &tinfo, uint32_t variant);
 
     static std::pair<uint8_t *,uint8_t *> get_evec_data_range(ptr dp);
-    static std::pair<uint8_t *,uint8_t *> get_ivec_data_range(ptr dp);
+    static std::pair<uint8_t *,uint8_t *> get_vec_data_range(ptr dp);
     static std::pair<ptr_pair,ptr_pair> get_evec_data_range(ptr_pair &dp);
-    static std::pair<ptr_pair,ptr_pair> get_ivec_data_range(ptr_pair &dp);
+    static std::pair<ptr_pair,ptr_pair> get_vec_data_range(ptr_pair &dp);
 
 public:
     U dp;
@@ -740,7 +738,6 @@ public:
     : ctxt< data<T,U> >(in_task, in_sp, in_params, in_tables), dp(in_dp) {}
 
     void walk_tag(bool align, tag_info &tinfo);
-    void walk_ivec(bool align, bool is_pod, size_align &elem_sa);
 
     void walk_struct(bool align, const uint8_t *end_sp) {
         static_cast<T *>(this)->walk_struct(align, end_sp);
@@ -749,6 +746,9 @@ public:
     void walk_evec(bool align, bool is_pod, uint16_t sp_size) {
         DATA_SIMPLE(void *, walk_evec(align, is_pod, sp_size));
     }
+    void walk_vec(bool align, bool is_pod, uint16_t sp_size) {
+        DATA_SIMPLE(void *, walk_vec(align, is_pod, sp_size));
+    }
 
     void walk_box(bool align)   { DATA_SIMPLE(void *, walk_box(align)); }
     void walk_port(bool align)  { DATA_SIMPLE(void *, walk_port(align)); }
@@ -815,27 +815,10 @@ data<T,U>::get_evec_data_range(ptr dp) {
 
 template<typename T,typename U>
 std::pair<uint8_t *,uint8_t *>
-data<T,U>::get_ivec_data_range(ptr dp) {
-    size_t fill = bump_dp<size_t>(dp);
-    bump_dp<size_t>(dp);    // Skip over alloc.
-    uint8_t *payload_dp = dp;
-    rust_ivec_payload payload = bump_dp<rust_ivec_payload>(dp);
-
-    uint8_t *start, *end;
-    if (!fill) {
-        if (!payload.ptr) {             // Zero length.
-            start = end = NULL;
-        } else {                        // On heap.
-            fill = payload.ptr->fill;
-            start = payload.ptr->data;
-            end = start + fill;
-        }
-    } else {                            // On stack.
-        start = payload_dp;
-        end = start + fill;
-    }
-
-    return std::make_pair(start, end);
+data<T,U>::get_vec_data_range(ptr dp) {
+    rust_vec* ptr = bump_dp<rust_vec*>(dp);
+    uint8_t* data = &ptr->data[0];
+    return std::make_pair(data, data + ptr->fill);
 }
 
 template<typename T,typename U>
@@ -850,9 +833,9 @@ data<T,U>::get_evec_data_range(ptr_pair &dp) {
 
 template<typename T,typename U>
 std::pair<ptr_pair,ptr_pair>
-data<T,U>::get_ivec_data_range(ptr_pair &dp) {
-    std::pair<uint8_t *,uint8_t *> fst = get_ivec_data_range(dp.fst);
-    std::pair<uint8_t *,uint8_t *> snd = get_ivec_data_range(dp.snd);
+data<T,U>::get_vec_data_range(ptr_pair &dp) {
+    std::pair<uint8_t *,uint8_t *> fst = get_vec_data_range(dp.fst);
+    std::pair<uint8_t *,uint8_t *> snd = get_vec_data_range(dp.snd);
     ptr_pair start(fst.first, snd.first);
     ptr_pair end(fst.second, snd.second);
     return std::make_pair(start, end);
@@ -860,24 +843,6 @@ data<T,U>::get_ivec_data_range(ptr_pair &dp) {
 
 template<typename T,typename U>
 void
-data<T,U>::walk_ivec(bool align, bool is_pod, size_align &elem_sa) {
-    if (!elem_sa.is_set())
-        elem_sa = size_of::get(*this);
-    else if (elem_sa.alignment == 8)
-        elem_sa.alignment = 4;  // FIXME: This is an awful hack.
-
-    // Get a pointer to the interior vector, and determine its size.
-    if (align) dp = align_to(dp, ALIGNOF(rust_ivec *));
-    U end_dp = dp + sizeof(rust_ivec) - sizeof(uintptr_t) + elem_sa.size * 4;
-
-    // Call to the implementation.
-    static_cast<T *>(this)->walk_ivec(align, is_pod, elem_sa);
-
-    dp = end_dp;
-}
-
-template<typename T,typename U>
-void
 data<T,U>::walk_tag(bool align, tag_info &tinfo) {
     size_of::compute_tag_size(*this, tinfo);
 
@@ -978,8 +943,8 @@ private:
         walk_vec(align, is_pod, get_evec_data_range(dp));
     }
 
-    void walk_ivec(bool align, bool is_pod, size_align &elem_sa) {
-        walk_vec(align, is_pod, get_ivec_data_range(dp));
+    void walk_vec(bool align, bool is_pod, uint16_t sp_size) {
+        walk_vec(align, is_pod, get_vec_data_range(dp));
     }
 
     void walk_tag(bool align, tag_info &tinfo, uint32_t tag_variant) {
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 9857f06231e..c94e993e7e6 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -62,16 +62,6 @@ upcall_log_str(rust_task *task, uint32_t level, rust_str *str) {
 }
 
 extern "C" CDECL void
-upcall_log_istr(rust_task *task, uint32_t level, rust_ivec *str) {
-    LOG_UPCALL_ENTRY(task);
-    if (task->sched->log_lvl < level)
-        return;
-    const char *buf = (const char *)
-        (str->fill ? str->payload.data : str->payload.ptr->data);
-    task->sched->log(task, level, "rust: %s", buf);
-}
-
-extern "C" CDECL void
 upcall_yield(rust_task *task) {
     LOG_UPCALL_ENTRY(task);
     LOG(task, comm, "upcall yield()");
@@ -354,69 +344,33 @@ upcall_get_type_desc(rust_task *task,
     return td;
 }
 
-/**
- * Resizes an interior vector that has been spilled to the heap.
- */
 extern "C" CDECL void
-upcall_ivec_resize_shared(rust_task *task,
-                          rust_ivec *v,
-                          size_t newsz) {
+upcall_vec_grow(rust_task* task, rust_vec** vp, size_t new_sz) {
     LOG_UPCALL_ENTRY(task);
-    scoped_lock with(task->sched->lock);
-    I(task->sched, !v->fill);
-
-    size_t new_alloc = next_power_of_two(newsz);
-    rust_ivec_heap *new_heap_part = (rust_ivec_heap *)
-        task->kernel->realloc(v->payload.ptr, new_alloc + sizeof(size_t));
-
-    new_heap_part->fill = newsz;
-    v->alloc = new_alloc;
-    v->payload.ptr = new_heap_part;
-}
-
-/**
- * Spills an interior vector to the heap.
- */
-extern "C" CDECL void
-upcall_ivec_spill_shared(rust_task *task,
-                         rust_ivec *v,
-                         size_t newsz) {
-    LOG_UPCALL_ENTRY(task);
-    scoped_lock with(task->sched->lock);
-    size_t new_alloc = next_power_of_two(newsz);
-
-    rust_ivec_heap *heap_part = (rust_ivec_heap *)
-        task->kernel->malloc(new_alloc + sizeof(size_t),
-                             "ivec spill shared");
-    heap_part->fill = newsz;
-    memcpy(&heap_part->data, v->payload.data, v->fill);
-
-    v->fill = 0;
-    v->alloc = new_alloc;
-    v->payload.ptr = heap_part;
+    // FIXME factor this into a utility function
+    if (new_sz > (*vp)->alloc) {
+        size_t new_alloc = next_power_of_two(new_sz);
+        *vp = (rust_vec*)task->kernel->realloc(*vp, new_alloc +
+                                                sizeof(rust_vec));
+        (*vp)->alloc = new_alloc;
+    }
+    (*vp)->fill = new_sz;
 }
 
 extern "C" CDECL void
-upcall_ivec_push(rust_task* task, rust_ivec* v, type_desc* elt_ty, void* x) {
+upcall_vec_push(rust_task* task, rust_vec** vp, type_desc* elt_ty,
+                 void* elt) {
     LOG_UPCALL_ENTRY(task);
-    bool is_interior = v->fill || !v->payload.ptr;
-    size_t sz = elt_ty->size;
-    size_t old_fill = is_interior ? v->fill : v->payload.ptr->fill;
-    size_t new_sz = sz + old_fill;
+    rust_vec* v = *vp;
+    size_t new_sz = v->fill + elt_ty->size;
     if (new_sz > v->alloc) {
-        if (is_interior) {
-            upcall_ivec_spill_shared(task, v, new_sz);
-            is_interior = false;
-        } else {
-            upcall_ivec_resize_shared(task, v, new_sz);
-        }
-    } else {
-        if (is_interior) v->fill = new_sz;
-        else v->payload.ptr->fill = new_sz;
+        size_t new_alloc = next_power_of_two(new_sz);
+        *vp = v = (rust_vec*)task->kernel->realloc(v, new_alloc +
+                                                    sizeof(rust_vec));
+        v->alloc = new_alloc;
     }
-    uint8_t* dataptr = is_interior ? &v->payload.data[0]
-                                   : &v->payload.ptr->data[0];
-    copy_elements(task, elt_ty, dataptr + old_fill, x, sz);
+    copy_elements(task, elt_ty, &v->data[0] + v->fill, elt, elt_ty->size);
+    v->fill += elt_ty->size;
 }
 
 
diff --git a/src/rt/rust_util.h b/src/rt/rust_util.h
index 6ab7d305a82..10cdbce6109 100644
--- a/src/rt/rust_util.h
+++ b/src/rt/rust_util.h
@@ -197,28 +197,18 @@ typedef rust_evec rust_str;
 // Interior vectors (rust-user-code level).
 
 struct
-rust_ivec_heap
-{
-    size_t fill;
-    uint8_t data[];
-};
-
-// Note that the payload is actually size 4*sizeof(elem), even when heapified
-union
-rust_ivec_payload
-{
-    rust_ivec_heap *ptr;    // if on heap
-    uint8_t data[];         // if on stack
-};
-
-struct
-rust_ivec
+rust_vec
 {
     size_t fill;    // in bytes; if zero, heapified
     size_t alloc;   // in bytes
-    rust_ivec_payload payload;
+    uint8_t data[0];
 };
 
+template <typename T>
+inline size_t vec_size(size_t elems) {
+    return sizeof(rust_vec) + sizeof(T) * elems;
+}
+
 //
 // Local Variables:
 // mode: C++
diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp
index b792121de35..add0e8da455 100644
--- a/src/rt/rust_uv.cpp
+++ b/src/rt/rust_uv.cpp
@@ -113,12 +113,12 @@ static socket_data *make_socket(rust_task *task, rust_chan *chan) {
 static uv_buf_t alloc_buffer(uv_stream_t *socket, size_t suggested_size) {
   LOG_CALLBACK_ENTRY(socket);
   uv_buf_t buf;
-  size_t actual_size = suggested_size + sizeof (rust_ivec_heap);
+  size_t actual_size = suggested_size + sizeof (rust_vec);
   socket_data *data = (socket_data*)socket->data;
   char *base =
     reinterpret_cast<char*>(data->task->kernel->malloc(actual_size,
                                                        "read buffer"));
-  buf.base = base + sizeof (rust_ivec_heap);
+  buf.base = base + sizeof (rust_vec);
   buf.len = suggested_size;
   return buf;
 }
@@ -129,26 +129,23 @@ static void read_progress(uv_stream_t *socket, ssize_t nread, uv_buf_t buf) {
   I(data->task->sched, data->reader != NULL);
   I(data->task->sched, nread <= ssize_t(buf.len));
 
-  rust_ivec_heap *base = reinterpret_cast<rust_ivec_heap*>(
-      reinterpret_cast<char*>(buf.base) - sizeof (rust_ivec_heap));
-  rust_ivec v;
-  v.fill = 0;
-  v.alloc = buf.len;
-  v.payload.ptr = base;
+  rust_vec *v = reinterpret_cast<rust_vec*>(
+      reinterpret_cast<char*>(buf.base) - sizeof (rust_vec));
+  v->alloc = buf.len;
 
   switch (nread) {
     case -1: // End of stream
-      base->fill = 0;
+      v->fill = 0;
       uv_read_stop(socket);
       break;
     case 0: // Nothing read
-      data->task->kernel->free(base);
+      data->task->kernel->free(v);
       return;
     default: // Got nread bytes
-      base->fill = nread;
+      v->fill = nread;
       break;
   }
-  data->reader->send(&v);
+  data->reader->send(v);
 }
 
 static void new_connection(uv_handle_t *socket, int status) {
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index 64617d3dfa5..3157b474b60 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -30,12 +30,6 @@ get_task_pointer
 get_task_trampoline
 get_time
 hack_allow_leaks
-ivec_copy_from_buf
-ivec_copy_from_buf_shared
-ivec_on_heap
-ivec_reserve
-ivec_reserve_shared
-ivec_to_ptr
 last_os_error
 leak
 migrate_alloc
@@ -70,7 +64,9 @@ str_buf
 str_byte_len
 str_from_buf
 str_from_cstr
-str_from_ivec
+str_from_vec
+vec_reserve_shared
+vec_from_buf_shared
 str_push_byte
 str_slice
 task_sleep
@@ -86,14 +82,13 @@ upcall_fail
 upcall_free
 upcall_get_type_desc
 upcall_grow_task
-upcall_ivec_resize_shared
-upcall_ivec_spill_shared
-upcall_ivec_push
+upcall_vec_grow
+upcall_vec_push
 upcall_kill
 upcall_log_double
 upcall_log_float
 upcall_log_int
-upcall_log_istr
+upcall_log_str
 upcall_log_str
 upcall_log_type
 upcall_malloc