about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-01-11 21:31:36 -0800
committerNiko Matsakis <niko@alum.mit.edu>2012-01-12 13:47:38 -0800
commite55aa6e5ef60369710d8b2e6f512b2ef84a8c548 (patch)
treefdb6e14395d7b7a95903bcfb6fab91a5fbf02d42
parentf4a3a3b8780d88e013a8916eea6cc9a8c2c5d890 (diff)
downloadrust-e55aa6e5ef60369710d8b2e6f512b2ef84a8c548.tar.gz
rust-e55aa6e5ef60369710d8b2e6f512b2ef84a8c548.zip
free uniq data we encounter on the sweep, walk thru them otherwise
-rw-r--r--src/comp/middle/shape.rs34
-rw-r--r--src/rt/rust_cc.cpp225
-rw-r--r--src/rt/rust_shape.cpp116
-rw-r--r--src/rt/rust_shape.h316
-rw-r--r--src/rt/rust_upcall.cpp2
-rw-r--r--src/test/run-pass/uniq-fn-leak.rs2
6 files changed, 433 insertions, 262 deletions
diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs
index 51bba4514b4..3f7c6cefca1 100644
--- a/src/comp/middle/shape.rs
+++ b/src/comp/middle/shape.rs
@@ -46,13 +46,18 @@ const shape_vec: u8 = 11u8;
 const shape_tag: u8 = 12u8;
 const shape_box: u8 = 13u8;
 const shape_struct: u8 = 17u8;
-const shape_fn: u8 = 18u8;
+const shape_box_fn: u8 = 18u8;
 const shape_obj: u8 = 19u8;
 const shape_res: u8 = 20u8;
 const shape_var: u8 = 21u8;
 const shape_uniq: u8 = 22u8;
 const shape_opaque_closure_ptr: u8 = 23u8; // the closure itself.
 const shape_iface: u8 = 24u8;
+const shape_uniq_fn: u8 = 25u8;
+const shape_stack_fn: u8 = 26u8;
+const shape_bare_fn: u8 = 27u8;
+const shape_tydesc: u8 = 28u8;
+const shape_send_tydesc: u8 = 29u8;
 
 // FIXME: This is a bad API in trans_common.
 fn C_u8(n: u8) -> ValueRef { ret trans_common::C_u8(n as uint); }
@@ -267,6 +272,14 @@ fn s_variant_tag_t(tcx: ty_ctxt) -> u8 {
     ret s_int(tcx);
 }
 
+fn s_tydesc(_tcx: ty_ctxt) -> u8 {
+    ret shape_tydesc;
+}
+
+fn s_send_tydesc(_tcx: ty_ctxt) -> u8 {
+    ret shape_send_tydesc;
+}
+
 fn mk_ctxt(llmod: ModuleRef) -> ctxt {
     let llshapetablesty = trans_common::T_named_struct("shapes");
     let llshapetables =
@@ -305,8 +318,10 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
       ty::ty_bot. { s += [shape_u8]; }
       ty::ty_int(ast::ty_i.) { s += [s_int(ccx.tcx)]; }
       ty::ty_float(ast::ty_f.) { s += [s_float(ccx.tcx)]; }
-      ty::ty_uint(ast::ty_u.) | ty::ty_ptr(_) | ty::ty_type. |
-      ty::ty_send_type. | ty::ty_native(_) { s += [s_uint(ccx.tcx)]; }
+      ty::ty_uint(ast::ty_u.) | ty::ty_ptr(_) |
+      ty::ty_native(_) { s += [s_uint(ccx.tcx)]; }
+      ty::ty_type. { s += [s_tydesc(ccx.tcx)]; }
+      ty::ty_send_type. { s += [s_send_tydesc(ccx.tcx)]; }
       ty::ty_int(ast::ty_i8.) { s += [shape_i8]; }
       ty::ty_uint(ast::ty_u16.) { s += [shape_u16]; }
       ty::ty_int(ast::ty_i16.) { s += [shape_i16]; }
@@ -418,8 +433,17 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
             }
         }
       }
-      ty::ty_fn(_) {
-        s += [shape_fn];
+      ty::ty_fn({proto: ast::proto_box., _}) {
+        s += [shape_box_fn];
+      }
+      ty::ty_fn({proto: ast::proto_uniq., _}) {
+        s += [shape_uniq_fn];
+      }
+      ty::ty_fn({proto: ast::proto_block., _}) {
+        s += [shape_stack_fn];
+      }
+      ty::ty_fn({proto: ast::proto_bare., _}) {
+        s += [shape_bare_fn];
       }
       ty::ty_opaque_closure_ptr(_) {
         s += [shape_opaque_closure_ptr];
diff --git a/src/rt/rust_cc.cpp b/src/rt/rust_cc.cpp
index 06a66366f78..1f99fe98f71 100644
--- a/src/rt/rust_cc.cpp
+++ b/src/rt/rust_cc.cpp
@@ -18,6 +18,9 @@
 // collection.
 #define RUST_CC_FREQUENCY   5000
 
+// defined in rust_upcall.cpp:
+void upcall_s_free_shared_type_desc(type_desc *td);
+
 namespace cc {
 
 // Internal reference count computation
@@ -70,7 +73,7 @@ class irc : public shape::data<irc,shape::ptr> {
                                   in_tables, in_data),
       ircs(in_ircs) {}
 
-    void walk_vec(bool is_pod, uint16_t sp_size) {
+    void walk_vec2(bool is_pod, uint16_t sp_size) {
         if (is_pod || shape::get_dp<void *>(dp) == NULL)
             return;     // There can't be any outbound pointers from this.
 
@@ -86,47 +89,63 @@ class irc : public shape::data<irc,shape::ptr> {
         }
     }
 
-    void walk_tag(shape::tag_info &tinfo, uint32_t tag_variant) {
-        shape::data<irc,shape::ptr>::walk_variant(tinfo, tag_variant);
+    void walk_tag2(shape::tag_info &tinfo, uint32_t tag_variant) {
+        shape::data<irc,shape::ptr>::walk_variant1(tinfo, tag_variant);
     }
 
-    void walk_box() {
-        shape::data<irc,shape::ptr>::walk_box_contents();
+    void walk_box2() {
+        shape::data<irc,shape::ptr>::walk_box_contents1();
     }
 
-    void walk_fn() {
-        // Record an irc for the environment box, but don't descend
-        // into it since it will be walked via the box's allocation
-        dp += sizeof(void *); // skip code pointer
-        uint8_t * box_ptr = shape::bump_dp<uint8_t *>(dp);
-        shape::ptr ref_count_dp(box_ptr);
-        maybe_record_irc(ref_count_dp);
+    void walk_uniq2() {
+        shape::data<irc,shape::ptr>::walk_uniq_contents1();
+    }
+
+    void walk_fn2(char code) {
+        switch (code) {
+          case shape::SHAPE_BOX_FN: {
+              // Record an irc for the environment box, but don't descend
+              // into it since it will be walked via the box's allocation
+              shape::bump_dp<void*>(dp); // skip over the code ptr
+              walk_box2();               // walk over the environment ptr
+              break;
+          }
+          case shape::SHAPE_BARE_FN:        // Does not close over data.
+          case shape::SHAPE_STACK_FN:       // Not reachable from heap.
+          case shape::SHAPE_UNIQ_FN: break; /* Can only close over sendable
+                                             * (and hence acyclic) data */
+          default: abort();
+        }
     }
 
-    void walk_obj() {
+    void walk_obj2() {
         dp += sizeof(void *); // skip vtable
         uint8_t *box_ptr = shape::bump_dp<uint8_t *>(dp);
         shape::ptr ref_count_dp(box_ptr);
         maybe_record_irc(ref_count_dp);
     }
 
-    void walk_iface() {
-        //shape::data<irc,shape::ptr>::walk_iface_contents(dp);
-        shape::data<irc,shape::ptr>::walk_box_contents();
+    void walk_iface2() {
+        walk_box2();
     }
 
-    void walk_res(const shape::rust_fn *dtor, unsigned n_params,
-                  const shape::type_param *params, const uint8_t *end_sp,
-                  bool live) {
+    void walk_tydesc2(char) {
+    }
+
+    void walk_res2(const shape::rust_fn *dtor, unsigned n_params,
+                   const shape::type_param *params, const uint8_t *end_sp,
+                   bool live) {
         while (this->sp != end_sp) {
             this->walk();
             align = true;
         }
     }
 
-    void walk_subcontext(irc &sub) { sub.walk(); }
+    void walk_subcontext2(irc &sub) { sub.walk(); }
 
-    void walk_box_contents(irc &sub, shape::ptr &ref_count_dp) {
+    void walk_uniq_contents2(irc &sub) { sub.walk(); }
+
+    void walk_box_contents2(irc &sub, shape::ptr &ref_count_dp) {
         maybe_record_irc(ref_count_dp);
 
         // Do not traverse the contents of this box; it's in the allocation
@@ -153,28 +172,28 @@ class irc : public shape::data<irc,shape::ptr> {
         }
     }
 
-    void walk_struct(const uint8_t *end_sp) {
+    void walk_struct2(const uint8_t *end_sp) {
         while (this->sp != end_sp) {
             this->walk();
             align = true;
         }
     }
 
-    void walk_variant(shape::tag_info &tinfo, uint32_t variant_id,
+    void walk_variant2(shape::tag_info &tinfo, uint32_t variant_id,
                       const std::pair<const uint8_t *,const uint8_t *>
                       variant_ptr_and_end);
 
     template<typename T>
-    inline void walk_number() { /* no-op */ }
+    inline void walk_number2() { /* no-op */ }
 
 public:
     static void compute_ircs(rust_task *task, irc_map &ircs);
 };
 
 void
-irc::walk_variant(shape::tag_info &tinfo, uint32_t variant_id,
-                  const std::pair<const uint8_t *,const uint8_t *>
-                  variant_ptr_and_end) {
+irc::walk_variant2(shape::tag_info &tinfo, uint32_t variant_id,
+                   const std::pair<const uint8_t *,const uint8_t *>
+                   variant_ptr_and_end) {
     irc sub(*this, variant_ptr_and_end.first, tinfo.params);
 
     assert(variant_id < 256);   // FIXME: Temporary sanity check.
@@ -305,7 +324,7 @@ class mark : public shape::data<mark,shape::ptr> {
                                    in_tables, in_data),
       marked(in_marked) {}
 
-    void walk_vec(bool is_pod, uint16_t sp_size) {
+    void walk_vec2(bool is_pod, uint16_t sp_size) {
         if (is_pod || shape::get_dp<void *>(dp) == NULL)
             return;     // There can't be any outbound pointers from this.
 
@@ -321,23 +340,39 @@ class mark : public shape::data<mark,shape::ptr> {
         }
     }
 
-    void walk_tag(shape::tag_info &tinfo, uint32_t tag_variant) {
-        shape::data<mark,shape::ptr>::walk_variant(tinfo, tag_variant);
+    void walk_tag2(shape::tag_info &tinfo, uint32_t tag_variant) {
+        shape::data<mark,shape::ptr>::walk_variant1(tinfo, tag_variant);
     }
 
-    void walk_box() {
-        shape::data<mark,shape::ptr>::walk_box_contents();
+    void walk_box2() {
+        shape::data<mark,shape::ptr>::walk_box_contents1();
     }
 
-    void walk_fn() {
-        shape::data<mark,shape::ptr>::walk_fn_contents(dp);
+    void walk_uniq2() {
+        shape::data<mark,shape::ptr>::walk_uniq_contents1();
     }
 
-    void walk_obj() {
-        shape::data<mark,shape::ptr>::walk_obj_contents(dp);
+    void walk_fn2(char code) {
+        switch (code) {
+          case shape::SHAPE_BOX_FN: {
+              // Record an irc for the environment box, but don't descend
+              // into it since it will be walked via the box's allocation
+              shape::data<mark,shape::ptr>::walk_fn_contents1(dp);
+              break;
+          }
+          case shape::SHAPE_BARE_FN:        // Does not close over data.
+          case shape::SHAPE_STACK_FN:       // Not reachable from heap.
+          case shape::SHAPE_UNIQ_FN: break; /* Can only close over sendable
+                                             * (and hence acyclic) data */
+          default: abort();
+        }
     }
 
-    void walk_res(const shape::rust_fn *dtor, unsigned n_params,
+    void walk_obj2() {
+        shape::data<mark,shape::ptr>::walk_obj_contents1(dp);
+    }
+
+    void walk_res2(const shape::rust_fn *dtor, unsigned n_params,
                   const shape::type_param *params, const uint8_t *end_sp,
                   bool live) {
         while (this->sp != end_sp) {
@@ -346,9 +381,18 @@ class mark : public shape::data<mark,shape::ptr> {
         }
     }
 
-    void walk_subcontext(mark &sub) { sub.walk(); }
+    void walk_iface2() {
+        walk_box2();
+    }
+
+    void walk_tydesc2(char) {
+    }
 
-    void walk_box_contents(mark &sub, shape::ptr &ref_count_dp) {
+    void walk_subcontext2(mark &sub) { sub.walk(); }
+
+    void walk_uniq_contents2(mark &sub) { sub.walk(); }
+
+    void walk_box_contents2(mark &sub, shape::ptr &ref_count_dp) {
         if (!ref_count_dp)
             return;
 
@@ -359,19 +403,19 @@ class mark : public shape::data<mark,shape::ptr> {
         sub.walk();
     }
 
-    void walk_struct(const uint8_t *end_sp) {
+    void walk_struct2(const uint8_t *end_sp) {
         while (this->sp != end_sp) {
             this->walk();
             align = true;
         }
     }
 
-    void walk_variant(shape::tag_info &tinfo, uint32_t variant_id,
+    void walk_variant2(shape::tag_info &tinfo, uint32_t variant_id,
                       const std::pair<const uint8_t *,const uint8_t *>
                       variant_ptr_and_end);
 
     template<typename T>
-    inline void walk_number() { /* no-op */ }
+    inline void walk_number2() { /* no-op */ }
 
 public:
     static void do_mark(rust_task *task, const std::vector<void *> &roots,
@@ -379,7 +423,7 @@ public:
 };
 
 void
-mark::walk_variant(shape::tag_info &tinfo, uint32_t variant_id,
+mark::walk_variant2(shape::tag_info &tinfo, uint32_t variant_id,
                    const std::pair<const uint8_t *,const uint8_t *>
                    variant_ptr_and_end) {
     mark sub(*this, variant_ptr_and_end.first, tinfo.params);
@@ -470,13 +514,13 @@ class sweep : public shape::data<sweep,shape::ptr> {
         : shape::data<sweep,shape::ptr>(in_task, in_align, in_sp,
                                         in_params, in_tables, in_data) {}
 
-    void walk_vec(bool is_pod, uint16_t sp_size) {
+    void walk_vec2(bool is_pod, uint16_t sp_size) {
         void *vec = shape::get_dp<void *>(dp);
-        walk_vec(is_pod, get_vec_data_range(dp));
+        walk_vec2(is_pod, get_vec_data_range(dp));
         task->kernel->free(vec);
     }
 
-    void walk_vec(bool is_pod,
+    void walk_vec2(bool is_pod,
                   const std::pair<shape::ptr,shape::ptr> &data_range) {
         sweep sub(*this, data_range.first);
         shape::ptr data_end = sub.end_dp = data_range.second;
@@ -486,50 +530,99 @@ class sweep : public shape::data<sweep,shape::ptr> {
         }
     }
 
-    void walk_tag(shape::tag_info &tinfo, uint32_t tag_variant) {
-        shape::data<sweep,shape::ptr>::walk_variant(tinfo, tag_variant);
-    }
-
-    void walk_box() {
-        shape::data<sweep,shape::ptr>::walk_box_contents();
+    void walk_tag2(shape::tag_info &tinfo, uint32_t tag_variant) {
+        shape::data<sweep,shape::ptr>::walk_variant1(tinfo, tag_variant);
+    }
+
+    void walk_uniq2() {
+        void *x = *((void **)dp);
+        // free contents first:
+        shape::data<sweep,shape::ptr>::walk_uniq_contents1();
+        // now free the ptr:
+        task->kernel->free(x);
+    }
+
+    void walk_box2() {
+        shape::data<sweep,shape::ptr>::walk_box_contents1();
+    }
+
+    void walk_fn2(char code) {
+        switch (code) {
+          case shape::SHAPE_UNIQ_FN: {
+              fn_env_pair pair = *(fn_env_pair*)dp;
+
+              // free closed over data:
+              // 
+              // FIXME--this is a bit sketchy, since there is an
+              // embedded tydesc that we will be using to walk the
+              // data, but it will be freed as we walk.  In the
+              // generated code we pull this desc out and free it
+              // later.  We may well want to do the same.  However,
+              // since all we use from the descr. is the "shape", I
+              // think we're ok.
+              shape::data<sweep,shape::ptr>::walk_fn_contents1(dp);
+
+              // now free the ptr:
+              task->kernel->free(pair.env);
+              break;
+          }
+          case shape::SHAPE_BOX_FN: {
+              // the box will be visited separately:
+              shape::bump_dp<void*>(dp); // skip over the code ptr
+              walk_box2();               // walk over the environment ptr
+              break;
+          }
+          case shape::SHAPE_BARE_FN:         // Does not close over data.
+          case shape::SHAPE_STACK_FN: break; // Not reachable from heap.
+          default: abort();
+        }
     }
 
-    void walk_fn() {
+    void walk_obj2() {
         return;
     }
 
-    void walk_obj() {
-        return;
+    void walk_iface2() {
+        walk_box2();
     }
 
-    void walk_iface() {
-        //shape::data<sweep,shape::ptr>::walk_iface_contents(dp);
-        shape::data<sweep,shape::ptr>::walk_box_contents();
+    void walk_tydesc2(char kind) {
+        type_desc *td = *(type_desc **)dp;
+        switch(kind) {
+          case shape::SHAPE_TYDESC:
+            break;
+          case shape::SHAPE_SEND_TYDESC:
+            upcall_s_free_shared_type_desc(td);
+            break;
+          default: abort();
+        }
     }
 
-    void walk_res(const shape::rust_fn *dtor, unsigned n_params,
-                  const shape::type_param *params, const uint8_t *end_sp,
-                  bool live) {
+    void walk_res2(const shape::rust_fn *dtor, unsigned n_params,
+                   const shape::type_param *params, const uint8_t *end_sp,
+                   bool live) {
         while (this->sp != end_sp) {
             this->walk();
             align = true;
         }
     }
 
-    void walk_subcontext(sweep &sub) { sub.walk(); }
+    void walk_subcontext2(sweep &sub) { sub.walk(); }
+
+    void walk_uniq_contents2(sweep &sub) { sub.walk(); }
 
-    void walk_box_contents(sweep &sub, shape::ptr &ref_count_dp) {
+    void walk_box_contents2(sweep &sub, shape::ptr &ref_count_dp) {
         return;
     }
 
-    void walk_struct(const uint8_t *end_sp) {
+    void walk_struct2(const uint8_t *end_sp) {
         while (this->sp != end_sp) {
             this->walk();
             align = true;
         }
     }
 
-    void walk_variant(shape::tag_info &tinfo, uint32_t variant_id,
+    void walk_variant2(shape::tag_info &tinfo, uint32_t variant_id,
                       const std::pair<const uint8_t *,const uint8_t *>
                       variant_ptr_and_end) {
         sweep sub(*this, variant_ptr_and_end.first, tinfo.params);
@@ -542,7 +635,7 @@ class sweep : public shape::data<sweep,shape::ptr> {
     }
 
     template<typename T>
-    inline void walk_number() { /* no-op */ }
+    inline void walk_number2() { /* no-op */ }
 
 public:
     static void do_sweep(rust_task *task, const std::set<void *> &marked);
diff --git a/src/rt/rust_shape.cpp b/src/rt/rust_shape.cpp
index ee7e389dc77..b7ab591ce04 100644
--- a/src/rt/rust_shape.cpp
+++ b/src/rt/rust_shape.cpp
@@ -73,7 +73,7 @@ type_param::from_obj_shape(const uint8_t *sp, ptr dp, arena &arena) {
 // A shape printer, useful for debugging
 
 void
-print::walk_tag(tag_info &tinfo) {
+print::walk_tag1(tag_info &tinfo) {
     DPRINT("tag%u", tinfo.tag_id);
     if (!tinfo.n_params)
         return;
@@ -94,7 +94,7 @@ print::walk_tag(tag_info &tinfo) {
 }
 
 void
-print::walk_struct(const uint8_t *end_sp) {
+print::walk_struct1(const uint8_t *end_sp) {
     DPRINT("(");
 
     bool first = true;
@@ -110,8 +110,8 @@ print::walk_struct(const uint8_t *end_sp) {
 }
 
 void
-print::walk_res(const rust_fn *dtor, unsigned n_params,
-                const type_param *params, const uint8_t *end_sp) {
+print::walk_res1(const rust_fn *dtor, unsigned n_params,
+                 const type_param *params, const uint8_t *end_sp) {
     DPRINT("res@%p", dtor);
 
     // Print type parameters.
@@ -151,7 +151,7 @@ print::walk_res(const rust_fn *dtor, unsigned n_params,
 }
 
 void
-print::walk_var(uint8_t param_index) {
+print::walk_var1(uint8_t param_index) {
     DPRINT("%c=", 'T' + param_index);
 
     const type_param *param = &params[param_index];
@@ -160,25 +160,25 @@ print::walk_var(uint8_t param_index) {
 }
 
 template<>
-void print::walk_number<uint8_t>()      { DPRINT("u8"); }
+void print::walk_number1<uint8_t>()      { DPRINT("u8"); }
 template<>
-void print::walk_number<uint16_t>()     { DPRINT("u16"); }
+void print::walk_number1<uint16_t>()     { DPRINT("u16"); }
 template<>
-void print::walk_number<uint32_t>()     { DPRINT("u32"); }
+void print::walk_number1<uint32_t>()     { DPRINT("u32"); }
 template<>
-void print::walk_number<uint64_t>()     { DPRINT("u64"); }
+void print::walk_number1<uint64_t>()     { DPRINT("u64"); }
 template<>
-void print::walk_number<int8_t>()       { DPRINT("i8"); }
+void print::walk_number1<int8_t>()       { DPRINT("i8"); }
 template<>
-void print::walk_number<int16_t>()      { DPRINT("i16"); }
+void print::walk_number1<int16_t>()      { DPRINT("i16"); }
 template<>
-void print::walk_number<int32_t>()      { DPRINT("i32"); }
+void print::walk_number1<int32_t>()      { DPRINT("i32"); }
 template<>
-void print::walk_number<int64_t>()      { DPRINT("i64"); }
+void print::walk_number1<int64_t>()      { DPRINT("i64"); }
 template<>
-void print::walk_number<float>()        { DPRINT("f32"); }
+void print::walk_number1<float>()        { DPRINT("f32"); }
 template<>
-void print::walk_number<double>()       { DPRINT("f64"); }
+void print::walk_number1<double>()       { DPRINT("f64"); }
 
 
 void
@@ -225,13 +225,13 @@ size_of::compute_tag_size(tag_info &tinfo) {
 }
 
 void
-size_of::walk_tag(tag_info &tinfo) {
+size_of::walk_tag1(tag_info &tinfo) {
     compute_tag_size(*this, tinfo);
     sa = tinfo.tag_sa;
 }
 
 void
-size_of::walk_struct(const uint8_t *end_sp) {
+size_of::walk_struct1(const uint8_t *end_sp) {
     size_align struct_sa(0, 1);
 
     bool first = true;
@@ -264,21 +264,21 @@ class cmp : public data<cmp,ptr_pair> {
     friend class data<cmp,ptr_pair>;
 
 private:
-    void walk_vec(bool is_pod,
-                  const std::pair<ptr_pair,ptr_pair> &data_range);
+    void walk_vec2(bool is_pod,
+                   const std::pair<ptr_pair,ptr_pair> &data_range);
 
-    inline void walk_subcontext(cmp &sub) {
+    inline void walk_subcontext2(cmp &sub) {
         sub.walk();
         result = sub.result;
     }
 
-    inline void walk_box_contents(cmp &sub, ptr_pair &ref_count_dp) {
+    inline void walk_box_contents2(cmp &sub, ptr_pair &ref_count_dp) {
         sub.align = true;
         sub.walk();
         result = sub.result;
     }
 
-    inline void walk_uniq_contents(cmp &sub) {
+    inline void walk_uniq_contents2(cmp &sub) {
         sub.align = true;
         sub.walk();
         result = sub.result;
@@ -338,32 +338,36 @@ public:
                          in_dp),
       result(0) {}
 
-    void walk_vec(bool is_pod, uint16_t sp_size) {
-        walk_vec(is_pod, get_vec_data_range(dp));
+    void walk_vec2(bool is_pod, uint16_t sp_size) {
+        walk_vec2(is_pod, get_vec_data_range(dp));
     }
 
-    void walk_box() {
-        data<cmp,ptr_pair>::walk_box_contents();
+    void walk_box2() {
+        data<cmp,ptr_pair>::walk_box_contents1();
     }
 
-    void walk_uniq() {
-        data<cmp,ptr_pair>::walk_uniq_contents();
+    void walk_uniq2() {
+        data<cmp,ptr_pair>::walk_uniq_contents1();
     }
 
-    void walk_fn()  { return cmp_two_pointers(); }
-    void walk_obj() { return cmp_two_pointers(); }
+    void walk_iface2() {
+        data<cmp,ptr_pair>::walk_box_contents1();
+    }
+
+    void walk_fn2(char) { return cmp_two_pointers(); }
+    void walk_obj2()    { return cmp_two_pointers(); }
 
-    void walk_tag(tag_info &tinfo, const data_pair<tag_variant_t> &tag_variants);
-    void walk_struct(const uint8_t *end_sp);
-    void walk_res(const rust_fn *dtor, uint16_t n_ty_params,
-                  const type_param *ty_params_sp, const uint8_t *end_sp,
-                  const data_pair<uintptr_t> &live);
-    void walk_variant(tag_info &tinfo, tag_variant_t variant_id,
-                      const std::pair<const uint8_t *,const uint8_t *>
-                      variant_ptr_and_end);
+    void walk_tag2(tag_info &tinfo, const data_pair<tag_variant_t> &tag_variants);
+    void walk_struct2(const uint8_t *end_sp);
+    void walk_res2(const rust_fn *dtor, uint16_t n_ty_params,
+                   const type_param *ty_params_sp, const uint8_t *end_sp,
+                   const data_pair<uintptr_t> &live);
+    void walk_variant2(tag_info &tinfo, tag_variant_t variant_id,
+                       const std::pair<const uint8_t *,const uint8_t *>
+                       variant_ptr_and_end);
 
     template<typename T>
-    void walk_number() { cmp_number(get_dp<T>(dp)); }
+    void walk_number2() { cmp_number(get_dp<T>(dp)); }
 };
 
 template<>
@@ -372,7 +376,7 @@ void cmp::cmp_number<int32_t>(const data_pair<int32_t> &nums) {
 }
 
 void
-cmp::walk_vec(bool is_pod, const std::pair<ptr_pair,ptr_pair> &data_range) {
+cmp::walk_vec2(bool is_pod, const std::pair<ptr_pair,ptr_pair> &data_range) {
     cmp sub(*this, data_range.first);
     ptr_pair data_end = sub.end_dp = data_range.second;
     while (!result && sub.dp < data_end) {
@@ -390,15 +394,15 @@ cmp::walk_vec(bool is_pod, const std::pair<ptr_pair,ptr_pair> &data_range) {
 }
 
 void
-cmp::walk_tag(tag_info &tinfo, const data_pair<tag_variant_t> &tag_variants) {
+cmp::walk_tag2(tag_info &tinfo, const data_pair<tag_variant_t> &tag_variants) {
     cmp_number(tag_variants);
     if (result != 0)
         return;
-    data<cmp,ptr_pair>::walk_variant(tinfo, tag_variants.fst);
+    data<cmp,ptr_pair>::walk_variant1(tinfo, tag_variants.fst);
 }
 
 void
-cmp::walk_struct(const uint8_t *end_sp) {
+cmp::walk_struct2(const uint8_t *end_sp) {
     while (!result && this->sp != end_sp) {
         this->walk();
         align = true;
@@ -406,16 +410,16 @@ cmp::walk_struct(const uint8_t *end_sp) {
 }
 
 void
-cmp::walk_res(const rust_fn *dtor, uint16_t n_ty_params,
+cmp::walk_res2(const rust_fn *dtor, uint16_t n_ty_params,
               const type_param *ty_params_sp, const uint8_t *end_sp,
               const data_pair<uintptr_t> &live) {
     abort();    // TODO
 }
 
 void
-cmp::walk_variant(tag_info &tinfo, tag_variant_t variant_id,
-                  const std::pair<const uint8_t *,const uint8_t *>
-                  variant_ptr_and_end) {
+cmp::walk_variant2(tag_info &tinfo, tag_variant_t variant_id,
+                   const std::pair<const uint8_t *,const uint8_t *>
+                   variant_ptr_and_end) {
     cmp sub(*this, variant_ptr_and_end.first, tinfo.params);
 
     const uint8_t *variant_end = variant_ptr_and_end.second;
@@ -430,7 +434,7 @@ cmp::walk_variant(tag_info &tinfo, tag_variant_t variant_id,
 // Polymorphic logging, for convenience
 
 void
-log::walk_string(const std::pair<ptr,ptr> &data) {
+log::walk_string2(const std::pair<ptr,ptr> &data) {
     out << prefix << "\"" << std::hex;
 
     ptr subdp = data.first;
@@ -447,7 +451,7 @@ log::walk_string(const std::pair<ptr,ptr> &data) {
 }
 
 void
-log::walk_struct(const uint8_t *end_sp) {
+log::walk_struct2(const uint8_t *end_sp) {
     out << prefix << "(";
     prefix = "";
 
@@ -463,10 +467,10 @@ log::walk_struct(const uint8_t *end_sp) {
 }
 
 void
-log::walk_vec(bool is_pod, const std::pair<ptr,ptr> &data) {
+log::walk_vec2(bool is_pod, const std::pair<ptr,ptr> &data) {
     if (peek() == SHAPE_U8) {
         sp++;   // It's a string. We handle this ourselves.
-        walk_string(data);
+        walk_string2(data);
         return;
     }
 
@@ -485,9 +489,9 @@ log::walk_vec(bool is_pod, const std::pair<ptr,ptr> &data) {
 }
 
 void
-log::walk_variant(tag_info &tinfo, tag_variant_t variant_id,
-                  const std::pair<const uint8_t *,const uint8_t *>
-                  variant_ptr_and_end) {
+log::walk_variant2(tag_info &tinfo, tag_variant_t variant_id,
+                   const std::pair<const uint8_t *,const uint8_t *>
+                   variant_ptr_and_end) {
     log sub(*this, variant_ptr_and_end.first, tinfo.params);
     const uint8_t *variant_end = variant_ptr_and_end.second;
 
@@ -503,8 +507,8 @@ log::walk_variant(tag_info &tinfo, tag_variant_t variant_id,
 }
 
 void
-log::walk_res(const rust_fn *dtor, unsigned n_params,
-              const type_param *params, const uint8_t *end_sp, bool live) {
+log::walk_res2(const rust_fn *dtor, unsigned n_params,
+               const type_param *params, const uint8_t *end_sp, bool live) {
     out << prefix << "res";
 
     if (this->sp == end_sp)
diff --git a/src/rt/rust_shape.h b/src/rt/rust_shape.h
index 0def948223f..b4efae9e704 100644
--- a/src/rt/rust_shape.h
+++ b/src/rt/rust_shape.h
@@ -46,12 +46,17 @@ const uint8_t SHAPE_VEC = 11u;
 const uint8_t SHAPE_TAG = 12u;
 const uint8_t SHAPE_BOX = 13u;
 const uint8_t SHAPE_STRUCT = 17u;
-const uint8_t SHAPE_FN = 18u;
+const uint8_t SHAPE_BOX_FN = 18u;
 const uint8_t SHAPE_OBJ = 19u;
 const uint8_t SHAPE_RES = 20u;
 const uint8_t SHAPE_VAR = 21u;
 const uint8_t SHAPE_UNIQ = 22u;
 const uint8_t SHAPE_IFACE = 24u;
+const uint8_t SHAPE_UNIQ_FN = 25u;
+const uint8_t SHAPE_STACK_FN = 26u;
+const uint8_t SHAPE_BARE_FN = 27u;
+const uint8_t SHAPE_TYDESC = 28u;
+const uint8_t SHAPE_SEND_TYDESC = 29u;
 
 #ifdef _LP64
 const uint8_t SHAPE_PTR = SHAPE_U64;
@@ -247,13 +252,13 @@ protected:
     inline size_align get_size_align(const uint8_t *&addr);
 
 private:
-    void walk_vec();
-    void walk_tag();
-    void walk_box();
-    void walk_uniq();
-    void walk_struct();
-    void walk_res();
-    void walk_var();
+    void walk_vec0();
+    void walk_tag0();
+    void walk_box0();
+    void walk_uniq0();
+    void walk_struct0();
+    void walk_res0();
+    void walk_var0();
 };
 
 
@@ -357,34 +362,40 @@ public:
 // Traversals
 
 #define WALK_NUMBER(c_type) \
-    static_cast<T *>(this)->template walk_number<c_type>()
+    static_cast<T *>(this)->template walk_number1<c_type>()
 #define WALK_SIMPLE(method) static_cast<T *>(this)->method()
 
 template<typename T>
 void
 ctxt<T>::walk() {
-  switch (*sp++) {
-    case SHAPE_U8:      WALK_NUMBER(uint8_t);   break;
-    case SHAPE_U16:     WALK_NUMBER(uint16_t);  break;
-    case SHAPE_U32:     WALK_NUMBER(uint32_t);  break;
-    case SHAPE_U64:     WALK_NUMBER(uint64_t);  break;
-    case SHAPE_I8:      WALK_NUMBER(int8_t);    break;
-    case SHAPE_I16:     WALK_NUMBER(int16_t);   break;
-    case SHAPE_I32:     WALK_NUMBER(int32_t);   break;
-    case SHAPE_I64:     WALK_NUMBER(int64_t);   break;
-    case SHAPE_F32:     WALK_NUMBER(float);     break;
-    case SHAPE_F64:     WALK_NUMBER(double);    break;
-    case SHAPE_VEC:     walk_vec();             break;
-    case SHAPE_TAG:     walk_tag();             break;
-    case SHAPE_BOX:     walk_box();             break;
-    case SHAPE_STRUCT:  walk_struct();          break;
-    case SHAPE_FN:      WALK_SIMPLE(walk_fn);   break;
-    case SHAPE_OBJ:     WALK_SIMPLE(walk_obj);  break;
-    case SHAPE_RES:     walk_res();             break;
-    case SHAPE_VAR:     walk_var();             break;
-    case SHAPE_UNIQ:    walk_uniq();            break;
-    case SHAPE_IFACE:   WALK_SIMPLE(walk_iface); break;
-    default:            abort();
+  char s = *sp++;
+  switch (s) {
+    case SHAPE_U8:       WALK_NUMBER(uint8_t);       break;
+    case SHAPE_U16:      WALK_NUMBER(uint16_t);      break;
+    case SHAPE_U32:      WALK_NUMBER(uint32_t);      break;
+    case SHAPE_U64:      WALK_NUMBER(uint64_t);      break;
+    case SHAPE_I8:       WALK_NUMBER(int8_t);        break;
+    case SHAPE_I16:      WALK_NUMBER(int16_t);       break;
+    case SHAPE_I32:      WALK_NUMBER(int32_t);       break;
+    case SHAPE_I64:      WALK_NUMBER(int64_t);       break;
+    case SHAPE_F32:      WALK_NUMBER(float);         break;
+    case SHAPE_F64:      WALK_NUMBER(double);        break;
+    case SHAPE_VEC:      walk_vec0();             break;
+    case SHAPE_TAG:      walk_tag0();             break;
+    case SHAPE_BOX:      walk_box0();             break;
+    case SHAPE_STRUCT:   walk_struct0();          break;
+    case SHAPE_OBJ:      WALK_SIMPLE(walk_obj1);      break;
+    case SHAPE_RES:      walk_res0();             break;
+    case SHAPE_VAR:      walk_var0();             break;
+    case SHAPE_UNIQ:     walk_uniq0();            break;
+    case SHAPE_IFACE:    WALK_SIMPLE(walk_iface1);    break;
+    case SHAPE_BOX_FN:
+    case SHAPE_UNIQ_FN:
+    case SHAPE_STACK_FN:
+    case SHAPE_BARE_FN:  static_cast<T*>(this)->walk_fn1(s); break;
+    case SHAPE_SEND_TYDESC:
+    case SHAPE_TYDESC:   static_cast<T*>(this)->walk_tydesc1(s); break;
+    default:             abort();
     }
 }
 
@@ -420,20 +431,20 @@ ctxt<T>::get_variant_sp(tag_info &tinfo, tag_variant_t variant_id) {
 
 template<typename T>
 void
-ctxt<T>::walk_vec() {
+ctxt<T>::walk_vec0() {
     bool is_pod = *sp++;
 
     uint16_t sp_size = get_u16_bump(sp);
     const uint8_t *end_sp = sp + sp_size;
 
-    static_cast<T *>(this)->walk_vec(is_pod, sp_size);
+    static_cast<T *>(this)->walk_vec1(is_pod, sp_size);
 
     sp = end_sp;
 }
 
 template<typename T>
 void
-ctxt<T>::walk_tag() {
+ctxt<T>::walk_tag0() {
     tag_info tinfo;
     tinfo.tag_id = get_u16_bump(sp);
 
@@ -465,45 +476,45 @@ ctxt<T>::walk_tag() {
     tinfo.params = params;
 
     // Call to the implementation.
-    static_cast<T *>(this)->walk_tag(tinfo);
+    static_cast<T *>(this)->walk_tag1(tinfo);
 }
 
 template<typename T>
 void
-ctxt<T>::walk_box() {
+ctxt<T>::walk_box0() {
     uint16_t sp_size = get_u16_bump(sp);
     const uint8_t *end_sp = sp + sp_size;
 
-    static_cast<T *>(this)->walk_box();
+    static_cast<T *>(this)->walk_box1();
 
     sp = end_sp;
 }
 
 template<typename T>
 void
-ctxt<T>::walk_uniq() {
+ctxt<T>::walk_uniq0() {
     uint16_t sp_size = get_u16_bump(sp);
     const uint8_t *end_sp = sp + sp_size;
 
-    static_cast<T *>(this)->walk_uniq();
+    static_cast<T *>(this)->walk_uniq1();
 
     sp = end_sp;
 }
 
 template<typename T>
 void
-ctxt<T>::walk_struct() {
+ctxt<T>::walk_struct0() {
     uint16_t sp_size = get_u16_bump(sp);
     const uint8_t *end_sp = sp + sp_size;
 
-    static_cast<T *>(this)->walk_struct(end_sp);
+    static_cast<T *>(this)->walk_struct1(end_sp);
 
     sp = end_sp;
 }
 
 template<typename T>
 void
-ctxt<T>::walk_res() {
+ctxt<T>::walk_res0() {
     uint16_t dtor_offset = get_u16_bump(sp);
     const rust_fn **resources =
         reinterpret_cast<const rust_fn **>(tables->resources);
@@ -523,16 +534,16 @@ ctxt<T>::walk_res() {
     uint16_t sp_size = get_u16_bump(sp);
     const uint8_t *end_sp = sp + sp_size;
 
-    static_cast<T *>(this)->walk_res(dtor, n_ty_params, params, end_sp);
+    static_cast<T *>(this)->walk_res1(dtor, n_ty_params, params, end_sp);
 
     sp = end_sp;
 }
 
 template<typename T>
 void
-ctxt<T>::walk_var() {
+ctxt<T>::walk_var0() {
     uint8_t param = *sp++;
-    static_cast<T *>(this)->walk_var(param);
+    static_cast<T *>(this)->walk_var1(param);
 }
 
 // A shape printer, useful for debugging
@@ -553,26 +564,44 @@ public:
           const rust_shape_tables *in_tables)
     : ctxt<print>(in_task, in_align, in_sp, in_params, in_tables) {}
 
-    void walk_tag(tag_info &tinfo);
-    void walk_struct(const uint8_t *end_sp);
-    void walk_res(const rust_fn *dtor, unsigned n_params,
-                  const type_param *params, const uint8_t *end_sp);
-    void walk_var(uint8_t param);
+    void walk_tag1(tag_info &tinfo);
+    void walk_struct1(const uint8_t *end_sp);
+    void walk_res1(const rust_fn *dtor, unsigned n_params,
+                   const type_param *params, const uint8_t *end_sp);
+    void walk_var1(uint8_t param);
 
-    void walk_vec(bool is_pod, uint16_t sp_size) {
+    void walk_vec1(bool is_pod, uint16_t sp_size) {
         DPRINT("vec<"); walk(); DPRINT(">");
     }
-    void walk_box() {
-        DPRINT("box<"); walk(); DPRINT(">");
+    void walk_uniq1() {
+        DPRINT("~<"); walk(); DPRINT(">");
+    }
+    void walk_box1() {
+        DPRINT("@<"); walk(); DPRINT(">");
     }
 
-    void walk_fn()  { DPRINT("fn"); }
-    void walk_obj() { DPRINT("obj"); }
-    void walk_iface() { DPRINT("iface"); }
-    void walk_closure();
+    void walk_fn1(char kind) {
+        switch(kind) {
+          case SHAPE_BARE_FN:  DPRINT("fn");  break;
+          case SHAPE_BOX_FN:   DPRINT("fn@"); break;
+          case SHAPE_UNIQ_FN:  DPRINT("fn~"); break;
+          case SHAPE_STACK_FN: DPRINT("fn&"); break;
+          default: abort();
+        }
+    }
+    void walk_obj1() { DPRINT("obj"); }
+    void walk_iface1() { DPRINT("iface"); }
+
+    void walk_tydesc1(char kind) {
+        switch(kind) {
+          case SHAPE_TYDESC: DPRINT("tydesc"); break;
+          case SHAPE_SEND_TYDESC: DPRINT("send-tydesc"); break;
+          default: abort();
+        }
+    }
 
     template<typename T>
-    void walk_number() {}
+    void walk_number1() {}
 
     template<typename T>
     static void print_cx(const T *cx) {
@@ -608,33 +637,35 @@ public:
             const rust_shape_tables *in_tables = NULL)
     : ctxt<size_of>(other, in_sp, in_params, in_tables) {}
 
-    void walk_tag(tag_info &tinfo);
-    void walk_struct(const uint8_t *end_sp);
+    void walk_tag1(tag_info &tinfo);
+    void walk_struct1(const uint8_t *end_sp);
 
-    void walk_box()     { sa.set(sizeof(void *),   sizeof(void *)); }
-    void walk_fn()      { sa.set(sizeof(void *)*2, sizeof(void *)); }
-    void walk_obj()     { sa.set(sizeof(void *)*2, sizeof(void *)); }
-    void walk_iface()   { sa.set(sizeof(void *),   sizeof(void *)); }
-    void walk_closure();
+    void walk_uniq1()       { sa.set(sizeof(void *),   sizeof(void *)); }
+    void walk_box1()        { sa.set(sizeof(void *),   sizeof(void *)); }
+    void walk_fn1(char)     { sa.set(sizeof(void *)*2, sizeof(void *)); }
+    void walk_obj1()        { sa.set(sizeof(void *)*2, sizeof(void *)); }
+    void walk_iface1()      { sa.set(sizeof(void *),   sizeof(void *)); }
+    void walk_tydesc1(char) { sa.set(sizeof(void *),   sizeof(void *)); }
+    void walk_closure1();
 
-    void walk_vec(bool is_pod, uint16_t sp_size) {
+    void walk_vec1(bool is_pod, uint16_t sp_size) {
         sa.set(sizeof(void *), sizeof(void *));
     }
 
-    void walk_var(uint8_t param_index) {
+    void walk_var1(uint8_t param_index) {
         const type_param *param = &params[param_index];
         size_of sub(*this, param->shape, param->params, param->tables);
         sub.walk();
         sa = sub.sa;
     }
 
-    void walk_res(const rust_fn *dtor, unsigned n_params,
-                  const type_param *params, const uint8_t *end_sp) {
+    void walk_res1(const rust_fn *dtor, unsigned n_params,
+                   const type_param *params, const uint8_t *end_sp) {
         abort();    // TODO
     }
 
     template<typename T>
-    void walk_number()  { sa.set(sizeof(T), alignof<T>()); }
+    void walk_number1()  { sa.set(sizeof(T), alignof<T>()); }
 
     void compute_tag_size(tag_info &tinfo);
 
@@ -819,12 +850,12 @@ public:
 protected:
     U end_dp;
 
-    void walk_box_contents();
-    void walk_uniq_contents();
-    void walk_fn_contents(ptr &dp);
-    void walk_obj_contents(ptr &dp);
-    void walk_iface_contents(ptr &dp);
-    void walk_variant(tag_info &tinfo, tag_variant_t variant);
+    void walk_box_contents1();
+    void walk_uniq_contents1();
+    void walk_fn_contents1(ptr &dp);
+    void walk_obj_contents1(ptr &dp);
+    void walk_iface_contents1(ptr &dp);
+    void walk_variant1(tag_info &tinfo, tag_variant_t variant);
 
     static std::pair<uint8_t *,uint8_t *> get_vec_data_range(ptr dp);
     static std::pair<ptr_pair,ptr_pair> get_vec_data_range(ptr_pair &dp);
@@ -840,87 +871,100 @@ public:
       dp(in_dp),
       end_dp() {}
 
-    void walk_tag(tag_info &tinfo);
+    void walk_tag1(tag_info &tinfo);
 
-    void walk_struct(const uint8_t *end_sp) {
-        static_cast<T *>(this)->walk_struct(end_sp);
+    void walk_struct1(const uint8_t *end_sp) {
+        static_cast<T *>(this)->walk_struct2(end_sp);
     }
 
-    void walk_vec(bool is_pod, uint16_t sp_size) {
-        DATA_SIMPLE(void *, walk_vec(is_pod, sp_size));
+    void walk_vec1(bool is_pod, uint16_t sp_size) {
+        DATA_SIMPLE(void *, walk_vec2(is_pod, sp_size));
     }
 
-    void walk_box()     { DATA_SIMPLE(void *, walk_box()); }
+    void walk_box1() { DATA_SIMPLE(void *, walk_box2()); }
 
-    void walk_uniq() { DATA_SIMPLE(void *, walk_uniq()); }
+    void walk_uniq1() { DATA_SIMPLE(void *, walk_uniq2()); }
 
-    void walk_fn() {
+    void walk_fn1(char code) {
         ALIGN_TO(alignof<void *>());
         U next_dp = dp + sizeof(void *) * 2;
-        static_cast<T *>(this)->walk_fn();
+        static_cast<T *>(this)->walk_fn2(code);
         dp = next_dp;
     }
 
-    void walk_obj() {
+    void walk_obj1() {
         ALIGN_TO(alignof<void *>());
         U next_dp = dp + sizeof(void *) * 2;
-        static_cast<T *>(this)->walk_obj();
+        static_cast<T *>(this)->walk_obj2();
+        dp = next_dp;
+    }
+
+    void walk_iface1() {
+        ALIGN_TO(alignof<void *>());
+        U next_dp = dp + sizeof(void *);
+        static_cast<T *>(this)->walk_iface2();
         dp = next_dp;
     }
 
-    void walk_iface() {
+    void walk_tydesc1(char kind) {
         ALIGN_TO(alignof<void *>());
         U next_dp = dp + sizeof(void *);
-        static_cast<T *>(this)->walk_iface();
+        static_cast<T *>(this)->walk_tydesc2(kind);
         dp = next_dp;
     }
 
-    void walk_res(const rust_fn *dtor, unsigned n_params,
-                  const type_param *params, const uint8_t *end_sp) {
+    void walk_res1(const rust_fn *dtor, unsigned n_params,
+                   const type_param *params, const uint8_t *end_sp) {
         typename U::template data<uintptr_t>::t live = bump_dp<uintptr_t>(dp);
         // Delegate to the implementation.
-        static_cast<T *>(this)->walk_res(dtor, n_params, params, end_sp,
+        static_cast<T *>(this)->walk_res2(dtor, n_params, params, end_sp,
                                          live);
     }
 
-    void walk_var(uint8_t param_index) {
+    void walk_var1(uint8_t param_index) {
         const type_param *param = &this->params[param_index];
         T sub(*static_cast<T *>(this), param->shape, param->params,
               param->tables);
-        static_cast<T *>(this)->walk_subcontext(sub);
+        static_cast<T *>(this)->walk_subcontext2(sub);
         dp = sub.dp;
     }
 
-    template<typename W>
-    void walk_number() { DATA_SIMPLE(W, walk_number<W>()); }
+    template<typename WN>
+    void walk_number1() { 
+        //DATA_SIMPLE(W, walk_number2<W>());
+        ALIGN_TO(alignof<WN>());
+        U end_dp = dp + sizeof(WN);
+        T* t = static_cast<T *>(this);
+        t->template walk_number2<WN>();
+        dp = end_dp;
+    }
 };
 
 template<typename T,typename U>
 void
-data<T,U>::walk_box_contents() {
+data<T,U>::walk_box_contents1() {
     typename U::template data<uint8_t *>::t box_ptr = bump_dp<uint8_t *>(dp);
-
     U ref_count_dp(box_ptr);
     T sub(*static_cast<T *>(this), ref_count_dp + sizeof(ref_cnt_t));
-    static_cast<T *>(this)->walk_box_contents(sub, ref_count_dp);
+    static_cast<T *>(this)->walk_box_contents2(sub, ref_count_dp);
 }
 
 template<typename T,typename U>
 void
-data<T,U>::walk_uniq_contents() {
+data<T,U>::walk_uniq_contents1() {
     typename U::template data<uint8_t *>::t box_ptr = bump_dp<uint8_t *>(dp);
     U data_ptr(box_ptr);
     T sub(*static_cast<T *>(this), data_ptr);
-    static_cast<T *>(this)->walk_uniq_contents(sub);
+    static_cast<T *>(this)->walk_uniq_contents2(sub);
 }
 
 template<typename T,typename U>
 void
-data<T,U>::walk_variant(tag_info &tinfo, tag_variant_t variant_id) {
+data<T,U>::walk_variant1(tag_info &tinfo, tag_variant_t variant_id) {
     std::pair<const uint8_t *,const uint8_t *> variant_ptr_and_end =
         this->get_variant_sp(tinfo, variant_id);
-    static_cast<T *>(this)->walk_variant(tinfo, variant_id,
-                                         variant_ptr_and_end);
+    static_cast<T *>(this)->walk_variant2(tinfo, variant_id,
+                                          variant_ptr_and_end);
 }
 
 template<typename T,typename U>
@@ -943,7 +987,7 @@ data<T,U>::get_vec_data_range(ptr_pair &dp) {
 
 template<typename T,typename U>
 void
-data<T,U>::walk_tag(tag_info &tinfo) {
+data<T,U>::walk_tag1(tag_info &tinfo) {
     size_of::compute_tag_size(*this, tinfo);
 
     if (tinfo.variant_count > 1)
@@ -957,14 +1001,14 @@ data<T,U>::walk_tag(tag_info &tinfo) {
     else
         tag_variant = 0;
 
-    static_cast<T *>(this)->walk_tag(tinfo, tag_variant);
+    static_cast<T *>(this)->walk_tag2(tinfo, tag_variant);
 
     dp = end_dp;
 }
 
 template<typename T,typename U>
 void
-data<T,U>::walk_fn_contents(ptr &dp) {
+data<T,U>::walk_fn_contents1(ptr &dp) {
     fn_env_pair pair = bump_dp<fn_env_pair>(dp);
     if (!pair.env)
         return;
@@ -982,7 +1026,7 @@ data<T,U>::walk_fn_contents(ptr &dp) {
 
 template<typename T,typename U>
 void
-data<T,U>::walk_obj_contents(ptr &dp) {
+data<T,U>::walk_obj_contents1(ptr &dp) {
     dp += sizeof(void *);   // Skip over the vtable.
 
     uint8_t *box_ptr = bump_dp<uint8_t *>(dp);
@@ -1003,7 +1047,7 @@ data<T,U>::walk_obj_contents(ptr &dp) {
 
 template<typename T,typename U>
 void
-data<T,U>::walk_iface_contents(ptr &dp) {
+data<T,U>::walk_iface_contents1(ptr &dp) {
     uint8_t *box_ptr = bump_dp<uint8_t *>(dp);
     if (!box_ptr) return;
     U ref_count_dp(box_ptr);
@@ -1017,7 +1061,7 @@ data<T,U>::walk_iface_contents(ptr &dp) {
     T sub(*static_cast<T *>(this), valtydesc->shape + 5, NULL, NULL,
           value_dp);
     sub.align = true;
-    static_cast<T *>(this)->walk_box_contents(sub, ref_count_dp);
+    static_cast<T *>(this)->walk_box_contents2(sub, ref_count_dp);
 }
 
 // Polymorphic logging, for convenience
@@ -1067,52 +1111,56 @@ private:
       out(other.out),
       prefix("") {}
 
-    void walk_vec(bool is_pod, uint16_t sp_size) {
+    void walk_vec2(bool is_pod, uint16_t sp_size) {
         if (!get_dp<void *>(dp))
             out << prefix << "(null)";
         else
-            walk_vec(is_pod, get_vec_data_range(dp));
+            walk_vec2(is_pod, get_vec_data_range(dp));
     }
 
-    void walk_tag(tag_info &tinfo, tag_variant_t tag_variant) {
+    void walk_tag2(tag_info &tinfo, tag_variant_t tag_variant) {
         out << prefix << "tag" << tag_variant;
-        data<log,ptr>::walk_variant(tinfo, tag_variant);
+        data<log,ptr>::walk_variant1(tinfo, tag_variant);
     }
 
-    void walk_box() {
+    void walk_box2() {
         out << prefix << "@";
         prefix = "";
-        data<log,ptr>::walk_box_contents();
+        data<log,ptr>::walk_box_contents1();
     }
 
-    void walk_uniq() {
+    void walk_uniq2() {
         out << prefix << "~";
         prefix = "";
-        data<log,ptr>::walk_uniq_contents();
+        data<log,ptr>::walk_uniq_contents1();
     }
 
-    void walk_fn() {
+    void walk_fn2(char kind) {
         out << prefix << "fn";
         prefix = "";
-        data<log,ptr>::walk_fn_contents(dp);
+        data<log,ptr>::walk_fn_contents1(dp);
     }
 
-    void walk_obj() {
+    void walk_obj2() {
         out << prefix << "obj";
         prefix = "";
-        data<log,ptr>::walk_obj_contents(dp);
+        data<log,ptr>::walk_obj_contents1(dp);
     }
 
-    void walk_iface() {
+    void walk_iface2() {
         out << prefix << "iface(";
         prefix = "";
-        data<log,ptr>::walk_iface_contents(dp);
+        data<log,ptr>::walk_iface_contents1(dp);
         out << prefix << ")";
     }
 
-    void walk_subcontext(log &sub) { sub.walk(); }
+    void walk_tydesc2(char kind) {
+        out << prefix << "tydesc";
+    }
+
+    void walk_subcontext2(log &sub) { sub.walk(); }
 
-    void walk_box_contents(log &sub, ptr &ref_count_dp) {
+    void walk_box_contents2(log &sub, ptr &ref_count_dp) {
         out << prefix;
         if (!ref_count_dp) {
             out << "(null)";
@@ -1122,23 +1170,23 @@ private:
         }
     }
 
-    void walk_uniq_contents(log &sub) {
+    void walk_uniq_contents2(log &sub) {
         out << prefix;
         sub.align = true;
         sub.walk();
     }
 
-    void walk_struct(const uint8_t *end_sp);
-    void walk_vec(bool is_pod, const std::pair<ptr,ptr> &data);
-    void walk_variant(tag_info &tinfo, tag_variant_t variant_id,
+    void walk_struct2(const uint8_t *end_sp);
+    void walk_vec2(bool is_pod, const std::pair<ptr,ptr> &data);
+    void walk_variant2(tag_info &tinfo, tag_variant_t variant_id,
                       const std::pair<const uint8_t *,const uint8_t *>
                       variant_ptr_and_end);
-    void walk_string(const std::pair<ptr,ptr> &data);
-    void walk_res(const rust_fn *dtor, unsigned n_params,
-                  const type_param *params, const uint8_t *end_sp, bool live);
+    void walk_string2(const std::pair<ptr,ptr> &data);
+    void walk_res2(const rust_fn *dtor, unsigned n_params,
+                   const type_param *params, const uint8_t *end_sp, bool live);
 
     template<typename T>
-    inline void walk_number() {
+    inline void walk_number2() {
         out << prefix;
         fmt_number(out, get_dp<T>(dp));
     }
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 423287e017e..12ef28065bd 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -279,7 +279,7 @@ upcall_create_shared_type_desc(type_desc *td) {
  */
 
 void upcall_s_free_shared_type_desc(type_desc *td)
-{
+{ // n.b.: invoked from rust_cc.cpp as well as generated code
     rust_task *task = rust_scheduler::get_task();
     LOG_UPCALL_ENTRY(task);
 
diff --git a/src/test/run-pass/uniq-fn-leak.rs b/src/test/run-pass/uniq-fn-leak.rs
index 7c9a6e7aca5..adf13c49a1e 100644
--- a/src/test/run-pass/uniq-fn-leak.rs
+++ b/src/test/run-pass/uniq-fn-leak.rs
@@ -6,12 +6,14 @@
 
     type pointy = {
         mutable a : maybe_pointy,
+        c : ~int,
         d : sendfn()->(),
     };
 
     fn empty_pointy() -> @pointy {
         ret @{
             mutable a : none,
+            c : ~22,
             d : sendfn()->(){},
         }
     }