]> git.lizzy.rs Git - rust.git/commitdiff
rejigger impl to have an opaque closure ptr rather than
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 6 Jan 2012 00:19:12 +0000 (16:19 -0800)
committerNiko Matsakis <niko@alum.mit.edu>
Sat, 7 Jan 2012 06:40:31 +0000 (22:40 -0800)
opaque closure

src/comp/back/abi.rs
src/comp/metadata/tydecode.rs
src/comp/metadata/tyencode.rs
src/comp/middle/shape.rs
src/comp/middle/trans.rs
src/comp/middle/trans_closure.rs
src/comp/middle/trans_common.rs
src/comp/middle/trans_impl.rs
src/comp/middle/ty.rs

index e5d93baa9d371193da846d5074afc6c3cd14169d..8e317ce0e9e5c079904f2d1a5966fbc550db221b 100644 (file)
@@ -26,8 +26,8 @@
 
 const frame_glue_fns_field_reloc: int = 2;
 
+// n.b. must be same as cbox_elt_refcnt
 const box_rc_field_refcnt: int = 0;
-
 const box_rc_field_body: int = 1;
 
 const general_code_alignment: int = 16;
 const fn_field_code: int = 0;
 const fn_field_box: int = 1;
 
-const closure_elt_tydesc: int = 0;
-const closure_elt_ty_params: int = 1;
-const closure_elt_bindings: int = 2;
+// closure_box, see trans_closure.rs
+//
+// n.b. the refcnt must be compatible with a normal box
+const cbox_elt_refcnt: int = 0;
+const cbox_elt_tydesc: int = 1;
+const cbox_elt_ty_params: int = 2;
+const cbox_elt_bindings: int = 3;
 
 const vec_elt_fill: int = 0;
 
index e339f4bc92e7f41935f5884c7e96f63934f39d6d..ae65c284fc2bebc5beb3da4f4f839dac8dabcc3b 100644 (file)
@@ -277,7 +277,14 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
       'E' { let def = parse_def(st, conv); ret ty::mk_native(st.tcx, def); }
       'Y' { ret ty::mk_type(st.tcx); }
       'y' { ret ty::mk_send_type(st.tcx); }
-      'C' { ret ty::mk_opaque_closure(st.tcx); }
+      'C' {
+        let ck = alt next(st) as char {
+          '&' { ty::closure_block }
+          '@' { ty::closure_shared }
+          '~' { ty::closure_send }
+        };
+        ret ty::mk_opaque_closure_ptr(st.tcx, ck);
+      }
       '#' {
         let pos = parse_hex(st);
         assert (next(st) as char == ':');
index 2ba572154c55807c51f085bd13412047552e3fb3..f5c4c91d0ac67d41826ffea318fba5ff44be81fe 100644 (file)
@@ -189,7 +189,9 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
       }
       ty::ty_type. { w.write_char('Y'); }
       ty::ty_send_type. { w.write_char('y'); }
-      ty::ty_opaque_closure. { w.write_char('C'); }
+      ty::ty_opaque_closure_ptr(ty::closure_block.) { w.write_str("C&"); }
+      ty::ty_opaque_closure_ptr(ty::closure_shared.) { w.write_str("C@"); }
+      ty::ty_opaque_closure_ptr(ty::closure_send.) { w.write_str("C~"); }
       ty::ty_constr(ty, cs) {
         w.write_str("A[");
         enc_ty(w, cx, ty);
index f78e0ffef85b62625129245792b90bd28ddc3141..43afb88361bc761dcab6f2787f8828cb77f65f81 100644 (file)
@@ -51,7 +51,7 @@
 const shape_res: u8 = 20u8;
 const shape_var: u8 = 21u8;
 const shape_uniq: u8 = 22u8;
-const shape_opaque_closure: u8 = 23u8; // the closure itself.
+const shape_opaque_closure_ptr: u8 = 23u8; // the closure itself.
 
 // FIXME: This is a bad API in trans_common.
 fn C_u8(n: u8) -> ValueRef { ret trans_common::C_u8(n as uint); }
@@ -419,8 +419,8 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
       ty::ty_fn(_) {
         s += [shape_fn];
       }
-      ty::ty_opaque_closure. {
-        s += [shape_opaque_closure];
+      ty::ty_opaque_closure_ptr(_) {
+        s += [shape_opaque_closure_ptr];
       }
     }
 
index 03adeb6843dd0bf78640bcc511c6c79bd9fe9d9f..fa4a1a729693ec59d04fbd4807714e6424091e16 100644 (file)
@@ -93,7 +93,7 @@ fn type_of_fn(cx: @crate_ctxt, sp: span, is_method: bool, inputs: [ty::arg],
     if is_method {
         atys += [T_ptr(cx.rust_object_type)];
     } else {
-        atys += [T_opaque_boxed_closure_ptr(cx)];
+        atys += [T_opaque_cbox_ptr(cx)];
     }
 
     // Args >2: ty params, if not acquired via capture...
@@ -202,8 +202,8 @@ fn type_of_inner(cx: @crate_ctxt, sp: span, t: ty::t)
         }
         T_struct(tys)
       }
-      ty::ty_opaque_closure. {
-        T_opaque_closure(cx)
+      ty::ty_opaque_closure_ptr(_) {
+        T_opaque_cbox_ptr(cx)
       }
       ty::ty_constr(subt,_) {
         // FIXME: could be a constraint on ty_fn
@@ -415,25 +415,13 @@ fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
 }
 
 fn size_of(bcx: @block_ctxt, t: ty::t) -> result {
-    assert !ty::type_has_opaque_size(bcx_tcx(bcx), t);
     let {bcx, sz, align: _} = metrics(bcx, t, none);
     rslt(bcx, sz)
 }
 
 fn align_of(bcx: @block_ctxt, t: ty::t) -> result {
-    assert !ty::type_has_opaque_size(bcx_tcx(bcx), t);
-    alt ty::struct(ccx.tcx, t) {
-      ty::ty_opaque_closure. {
-        // Hack: the alignment of an opaque closure is always defined as the
-        // alignment of a pointer.  This is not, however, strictly correct,
-        // depending on your point of view.  
-        llalign_of(bcx, T_ptr(T_i8()));
-      }
-      _ {
-        let {bcx, sz: _, align} = metrics(bcx, t, none);
-        rslt(bcx, align)
-      }
-    }
+    let {bcx, sz: _, align} = metrics(bcx, t, none);
+    rslt(bcx, align)
 }
 
 // Computes the size/alignment of the type `t`.  `opt_v`, if provided, should
@@ -443,8 +431,6 @@ fn align_of(bcx: @block_ctxt, t: ty::t) -> result {
 // instance is required.
 fn metrics(bcx: @block_ctxt, t: ty::t, opt_v: option<ValueRef>)
     -> metrics_result {
-    assert (option::is_some(opt_v) ||
-            !ty::type_has_opaque_size(bcx_tcx(bcx), t));
     let ccx = bcx_ccx(bcx);
     if check type_has_static_size(ccx, t) {
         let sp = bcx.sp;
@@ -651,29 +637,6 @@ fn c_struct_metrics(bcx: @block_ctxt,
         let total_align = C_int(bcx_ccx(bcx), 1); // FIXME: stub
         ret {bcx: bcx, sz: total_size, align: total_align};
       }
-      ty::ty_opaque_closure. {
-        // Unlike most other types, the type of an opaque closure does not
-        // fully specify its size.  This is because the opaque closure type
-        // only says that this is a closure over some data, but doesn't say
-        // how much data there is (hence the word opaque).  This is an
-        // unavoidable consequence of the way that closures encapsulate the
-        // closed over data.  Therefore the only way to know the
-        // size/alignment of a particular opaque closure instance is to load
-        // the type descriptor from the instance and consult its
-        // size/alignment fields.  Note that it is meaningless to say "what is
-        // the size of the type opaque closure?" One can only ask "what is the
-        // size of this particular opaque closure?"
-        let v = alt opt_v {
-          none. { fail "Require value to compute metrics of opaque closures"; }
-          some(v) { v }
-        };
-        let v = PointerCast(bcx, v, T_ptr(T_opaque_closure(bcx_ccx(bcx))));
-        let tdptrptr = GEPi(bcx, v, [0, abi::closure_elt_tydesc]);
-        let tdptr = Load(bcx, tdptrptr);
-        let sz = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_size]));
-        let align = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_align]));
-        ret { bcx: bcx, sz: sz, align: align };
-      }
     }
 }
 
@@ -1354,9 +1317,8 @@ fn make_take_glue(cx: @block_ctxt, v: ValueRef, t: ty::t) {
       ty::ty_native_fn(_, _) | ty::ty_fn(_) {
         trans_closure::make_fn_glue(bcx, v, t, take_ty)
       }
-      ty::ty_opaque_closure. {
-        trans_closure::call_opaque_closure_glue(
-            bcx, v, abi::tydesc_field_take_glue)
+      ty::ty_opaque_closure_ptr(ck) {
+        trans_closure::make_opaque_cbox_take_glue(bcx, ck, v)
       }
       _ when ty::type_is_structural(bcx_tcx(bcx), t) {
         iter_structural_ty(bcx, v, t, take_ty)
@@ -1429,9 +1391,8 @@ fn make_free_glue(bcx: @block_ctxt, v: ValueRef, t: ty::t) {
       ty::ty_native_fn(_, _) | ty::ty_fn(_) {
         trans_closure::make_fn_glue(bcx, v, t, free_ty)
       }
-      ty::ty_opaque_closure. {
-        trans_closure::call_opaque_closure_glue(
-            bcx, v, abi::tydesc_field_free_glue)
+      ty::ty_opaque_closure_ptr(ck) {
+        trans_closure::make_opaque_cbox_free_glue(bcx, ck, v)
       }
       _ { bcx }
     };
@@ -1458,9 +1419,8 @@ fn make_drop_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) {
           ty::ty_native_fn(_, _) | ty::ty_fn(_) {
             trans_closure::make_fn_glue(bcx, v0, t, drop_ty)
           }
-          ty::ty_opaque_closure. {
-            trans_closure::call_opaque_closure_glue(
-                bcx, v0, abi::tydesc_field_drop_glue)
+          ty::ty_opaque_closure_ptr(ck) {
+            trans_closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
           }
           _ {
             if ty::type_needs_drop(ccx.tcx, t) &&
@@ -2617,7 +2577,7 @@ fn trans_do_while(cx: @block_ctxt, body: ast::blk, cond: @ast::expr) ->
                           generic: option::t<generic_info>};
 
 fn null_env_ptr(bcx: @block_ctxt) -> ValueRef {
-    C_null(T_opaque_boxed_closure_ptr(bcx_ccx(bcx)))
+    C_null(T_opaque_cbox_ptr(bcx_ccx(bcx)))
 }
 
 fn lval_from_local_var(bcx: @block_ctxt, r: local_var_result) -> lval_result {
@@ -3274,7 +3234,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
     let llenv, dict_param = none;
     alt f_res.env {
       null_env. {
-        llenv = llvm::LLVMGetUndef(T_opaque_boxed_closure_ptr(bcx_ccx(cx)));
+        llenv = llvm::LLVMGetUndef(T_opaque_cbox_ptr(bcx_ccx(cx)));
       }
       obj_env(e) { llenv = e; }
       dict_env(dict, e) { llenv = e; dict_param = some(dict); }
@@ -5257,7 +5217,7 @@ fn fill_fn_pair(bcx: @block_ctxt, pair: ValueRef, llfn: ValueRef,
     Store(bcx, llfn, code_cell);
     let env_cell = GEPi(bcx, pair, [0, abi::fn_field_box]);
     let llenvblobptr =
-        PointerCast(bcx, llenvptr, T_opaque_boxed_closure_ptr(ccx));
+        PointerCast(bcx, llenvptr, T_opaque_cbox_ptr(ccx));
     Store(bcx, llenvblobptr, env_cell);
 }
 
index 831a5b4e41e8b3d12c545e0c5cd26a9f4fd68691..57791f17ee0f6e059b740f3246e60723d0e30930 100644 (file)
 // roughly as follows:
 //
 // struct closure_box {
-//    unsigned ref_count; // only used for sharid environments
-//    struct closure {
-//      type_desc *tydesc;         // descriptor for the "struct closure" type
-//      type_desc *bound_tdescs[]; // bound descriptors
-//      struct {
-//          upvar1_t upvar1;
-//          ...
-//          upvarN_t upvarN;
-//      } bound_data;
-//   };
+//   unsigned ref_count; // only used for shared environments
+//   type_desc *tydesc;  // descriptor for the "struct closure_box" type
+//   type_desc *bound_tdescs[]; // bound descriptors
+//   struct {
+//     upvar1_t upvar1;
+//     ...
+//     upvarN_t upvarN;
+//   } bound_data;
 // };
 //
-// NB: this struct is defined in the code in trans_common::T_closure()
-// and mk_closure_ty() below.  The former defines the LLVM version and
-// the latter the Rust equivalent.  It occurs to me that these could
-// perhaps be unified, but currently they are not.
-//
-// Note that the closure carries a type descriptor that describes
-// itself.  Trippy.  This is needed because the precise types of the
-// closed over data are lost in the closure type (`fn(T)->U`), so if
-// we need to take/drop, we must know what data is in the upvars and
-// so forth.
+// Note that the closure carries a type descriptor that describes the
+// closure itself.  Trippy.  This is needed because the precise types
+// of the closed over data are lost in the closure type (`fn(T)->U`),
+// so if we need to take/drop, we must know what data is in the upvars
+// and so forth.  This struct is defined in the code in mk_closure_tys()
+// below.
 //
 // The allocation strategy for this closure depends on the closure
 // type.  For a sendfn, the closure (and the referenced type
 // easier when upcasting to block(T)->U, in the shape code, and so
 // forth.
 //
+// ## Opaque Closures ##
+//
+// One interesting part of closures is that they encapsulate the data
+// that they close over.  So when I have a ptr to a closure, I do not
+// know how many type descriptors it contains nor what upvars are
+// captured within.  That means I do not know precisely how big it is
+// nor where its fields are located.  This is called an "opaque
+// closure".
+//
+// Typically an opaque closure suffices because I only manipulate it
+// by ptr.  The routine trans_common::T_opaque_cbox_ptr() returns an
+// appropriate type for such an opaque closure; it allows access to the
+// first two fields, but not the others.
+//
+// But sometimes, such as when cloning or freeing a closure, we need
+// to know the full information.  That is where the type descriptor
+// that defines the closure comes in handy.  We can use its take and
+// drop glue functions to allocate/free data as needed.
+//
+// ## Subtleties concerning alignment ##
+//
+// You'll note that the closure_box structure is a flat structure with
+// four fields.  In some ways, it would be more convenient to use a nested
+// structure like so:
+//
+// struct {
+//   int;
+//   struct {
+//     type_desc*;
+//     type_desc*[];
+//     bound_data;
+// } }
+//
+// This would be more convenient because it would allow us to use more
+// of the existing infrastructure: we could treat the inner struct as
+// a type and then hvae a boxed variant (which would add the int) etc.
+// However, there is one subtle problem with this: grouping the latter
+// 3 fields into an inner struct causes the alignment of the entire
+// struct to be the max alignment of the bound_data.  This will
+// therefore vary from closure to closure.  That would mean that we
+// cannot reliably locate the initial type_desc* in an opaque closure!
+// That's definitely a bad thing.  Therefore, I have elected to create
+// a flat structure, even though it means some mild amount of code
+// duplication (however, we used to do it the other way, and we were
+// jumping through about as many hoops just trying to wedge a ref
+// count into a unique pointer, so it's kind of a wash in the end).
+//
 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 tag environment_value {
     env_ref(ValueRef, ty::t, lval_kind);
 }
 
-// Given a closure ty, emits a corresponding tuple ty
-fn mk_closure_ty(tcx: ty::ctxt,
-                 ck: ty::closure_kind,
-                 ty_params: [fn_ty_param],
-                 bound_data_ty: ty::t)
-    -> ty::t {
-    let tydesc_ty = alt ck {
+fn mk_tydesc_ty(tcx: ty::ctxt, ck: ty::closure_kind) -> ty::t {
+    ret alt ck {
       ty::closure_block. | ty::closure_shared. { ty::mk_type(tcx) }
       ty::closure_send. { ty::mk_send_type(tcx) }
     };
+}
+
+// Given a closure ty, emits a corresponding tuple ty
+fn mk_closure_tys(tcx: ty::ctxt,
+                  ck: ty::closure_kind,
+                  ty_params: [fn_ty_param],
+                  bound_values: [environment_value]) -> (ty::t, [ty::t]) {
+    let bound_tys = [];
+
+    let tydesc_ty =
+        mk_tydesc_ty(tcx, ck);
+
+    // Compute the closed over tydescs
     let param_ptrs = [];
     for tp in ty_params {
         param_ptrs += [tydesc_ty];
@@ -96,26 +145,98 @@ fn mk_closure_ty(tcx: ty::ctxt,
             for dict in dicts { param_ptrs += [tydesc_ty]; }
         }
     }
-    ty::mk_tup(tcx, [tydesc_ty, ty::mk_tup(tcx, param_ptrs), bound_data_ty])
-}
 
-fn shared_opaque_closure_box_ty(tcx: ty::ctxt) -> ty::t {
-    let opaque_closure_ty = ty::mk_opaque_closure(tcx);
-    ret ty::mk_imm_box(tcx, opaque_closure_ty);
+    // Compute the closed over data
+    for bv in bound_values {
+        bound_tys += [alt bv {
+            env_copy(_, t, _) { t }
+            env_move(_, t, _) { t }
+            env_ref(_, t, _) { t }
+            env_expr(e) { ty::expr_ty(tcx, e) }
+        }];
+    }
+    let bound_data_ty = ty::mk_tup(tcx, bound_tys);
+
+    // closure_ty == ref count, data tydesc, typarams, bound data
+    let closure_ty =
+        ty::mk_tup(tcx, [ty::mk_int(tcx), tydesc_ty,
+                         ty::mk_tup(tcx, param_ptrs), bound_data_ty]);
+
+    ret (closure_ty, bound_tys);
 }
 
-fn send_opaque_closure_box_ty(tcx: ty::ctxt) -> ty::t {
-    let opaque_closure_ty = ty::mk_opaque_closure(tcx);
-    let tup_ty = ty::mk_tup(tcx, [ty::mk_int(tcx), opaque_closure_ty]);
-    ret ty::mk_uniq(tcx, {ty: tup_ty, mut: ast::imm});
+fn allocate_cbox(bcx: @block_ctxt,
+                 ck: ty::closure_kind,
+                 cbox_ty: ty::t)
+    -> (@block_ctxt, ValueRef, [ValueRef]) {
+
+    fn alloc_in_heap(bcx: @block_ctxt,
+                     cbox_ty: ty::t,
+                     shared: bool,
+                     &temp_cleanups: [ValueRef])
+        -> (@block_ctxt, ValueRef) {
+
+        // n.b. If you are wondering why we don't use
+        // trans_malloc_boxed() or alloc_uniq(), see the section about
+        // "Subtleties concerning alignment" in the big comment at the
+        // top of the file.
+
+        let {bcx, val:llsz} = size_of(bcx, cbox_ty);
+        let ti = none;
+        let {bcx, val:lltydesc} =
+            get_tydesc(bcx, cbox_ty, true, tps_normal, ti).result;
+        let malloc =
+            if shared { bcx_ccx(bcx).upcalls.shared_malloc }
+            else { bcx_ccx(bcx).upcalls.malloc };
+        let box = Call(bcx, malloc, [llsz, lltydesc]);
+        add_clean_free(bcx, box, shared);
+        temp_cleanups += [box];
+        (bcx, box)
+    }
+
+    let ccx = bcx_ccx(bcx);
+
+    // Allocate the box:
+    let temp_cleanups = [];
+    let (bcx, box, rc) = alt ck {
+      ty::closure_shared. {
+        let (bcx, box) = alloc_in_heap(bcx, cbox_ty, false, temp_cleanups);
+        (bcx, box, 1)
+      }
+      ty::closure_send. {
+        let (bcx, box) = alloc_in_heap(bcx, cbox_ty, true, temp_cleanups);
+        (bcx, box, 0xdeadc0de) // use arbitrary value for debugging
+      }
+      ty::closure_block. {
+        let {bcx, val: box} = trans::alloc_ty(bcx, cbox_ty);
+        (bcx, box, 0xdeadc0df) // use arbitrary value for debugging
+      }
+    };
+
+    // Initialize ref count
+    let box = PointerCast(bcx, box, T_opaque_cbox_ptr(ccx));
+    let ref_cnt = GEPi(bcx, box, [0, abi::box_rc_field_refcnt]);
+    Store(bcx, C_int(ccx, rc), ref_cnt);
+
+    ret (bcx, box, temp_cleanups);
 }
 
 type closure_result = {
-    llbox: ValueRef,  // llvalue of boxed environment
-    box_ty: ty::t,    // type of boxed environment
-    bcx: @block_ctxt  // final bcx
+    llbox: ValueRef,     // llvalue of ptr to closure
+    cboxptr_ty: ty::t,   // type of ptr to closure
+    bcx: @block_ctxt     // final bcx
 };
 
+fn cast_if_we_can(bcx: @block_ctxt, llbox: ValueRef, t: ty::t) -> ValueRef {
+    let ccx = bcx_ccx(bcx);
+    if check type_has_static_size(ccx, t) {
+        let llty = type_of(ccx, bcx.sp, t);
+        ret PointerCast(bcx, llbox, llty);
+    } else {
+        ret llbox;
+    }
+}
+
 // Given a block context and a list of tydescs and values to bind
 // construct a closure out of them. If copying is true, it is a
 // heap allocated closure that copies the upvars into environment.
@@ -126,16 +247,6 @@ fn store_environment(
     ck: ty::closure_kind)
     -> closure_result {
 
-    fn dummy_environment_box(bcx: @block_ctxt, r: result)
-        -> (@block_ctxt, ValueRef, ValueRef) {
-        // Prevent glue from trying to free this.
-        let ccx = bcx_ccx(bcx);
-        let ref_cnt = GEPi(bcx, r.val, [0, abi::box_rc_field_refcnt]);
-        Store(r.bcx, C_int(ccx, 2), ref_cnt);
-        let closure = GEPi(r.bcx, r.val, [0, abi::box_rc_field_body]);
-        (r.bcx, closure, r.val)
-    }
-
     fn maybe_clone_tydesc(bcx: @block_ctxt,
                           ck: ty::closure_kind,
                           td: ValueRef) -> ValueRef {
@@ -152,61 +263,17 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
     //let ccx = bcx_ccx(bcx);
     let tcx = bcx_tcx(bcx);
 
-    // First, synthesize a tuple type containing the types of all the
-    // bound expressions.
-    // bindings_ty = [bound_ty1, bound_ty2, ...]
-    let bound_tys = [];
-    for bv in bound_values {
-        bound_tys += [alt bv {
-            env_copy(_, t, _) { t }
-            env_move(_, t, _) { t }
-            env_ref(_, t, _) { t }
-            env_expr(e) { ty::expr_ty(tcx, e) }
-        }];
-    }
-    let bound_data_ty = ty::mk_tup(tcx, bound_tys);
-    let closure_ty =
-        mk_closure_ty(tcx, ck, lltyparams, bound_data_ty);
-
-    let temp_cleanups = [];
+    // compute the shape of the closure
+    let (cbox_ty, bound_tys) =
+        mk_closure_tys(tcx, ck, lltyparams, bound_values);
 
-    // Allocate a box that can hold something closure-sized.
-    //
-    // For now, no matter what kind of closure we have, we always allocate
-    // space for a ref cnt in the closure.  If the closure is a block or
-    // unique closure, this ref count isn't really used: we initialize it to 2
-    // so that it will never drop to zero.  This is a hack and could go away
-    // but then we'd have to modify the code to do the right thing when
-    // casting from a shared closure to a block.
-    let (bcx, closure, box) = alt ck {
-      ty::closure_shared. {
-        let r = trans::trans_malloc_boxed(bcx, closure_ty);
-        add_clean_free(bcx, r.box, false);
-        temp_cleanups += [r.box];
-        (r.bcx, r.body, r.box)
-      }
-      ty::closure_send. {
-        // Dummy up a box in the exchange heap.
-        let tup_ty = ty::mk_tup(tcx, [ty::mk_int(tcx), closure_ty]);
-        let box_ty = ty::mk_uniq(tcx, {ty: tup_ty, mut: ast::imm});
-        check trans_uniq::type_is_unique_box(bcx, box_ty);
-        let r = trans_uniq::alloc_uniq(bcx, box_ty);
-        add_clean_free(bcx, r.val, true);
-        temp_cleanups += [r.val];
-        dummy_environment_box(bcx, r)
-      }
-      ty::closure_block. {
-        // Dummy up a box on the stack,
-        let ty = ty::mk_tup(tcx, [ty::mk_int(tcx), closure_ty]);
-        let r = trans::alloc_ty(bcx, ty);
-        dummy_environment_box(bcx, r)
-      }
-    };
+    // allocate closure in the heap
+    let (bcx, llbox, temp_cleanups) = allocate_cbox(bcx, ck, cbox_ty);
 
-    // Store bindings tydesc.
+    // store data tydesc.
     alt ck {
       ty::closure_shared. | ty::closure_send. {
-        let bound_tydesc = GEPi(bcx, closure, [0, abi::closure_elt_tydesc]);
+        let bound_tydesc = GEPi(bcx, llbox, [0, abi::cbox_elt_tydesc]);
         let ti = none;
 
         // NDM I believe this is the correct value,
@@ -218,7 +285,7 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
 
         let tps = tps_normal;
         let {result:closure_td, _} =
-            trans::get_tydesc(bcx, closure_ty, true, tps, ti);
+            trans::get_tydesc(bcx, cbox_ty, true, tps, ti);
         trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, ti);
         trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
         trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
@@ -229,16 +296,18 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
       ty::closure_block. { /* skip this for blocks, not really relevant */ }
     }
 
-    check type_is_tup_like(bcx, closure_ty);
-    let box_ty = ty::mk_imm_box(bcx_tcx(bcx), closure_ty);
+    // cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a
+    // tuple.  This could be a ptr in uniq or a box or on stack,
+    // whatever.
+    let cboxptr_ty = ty::mk_ptr(tcx, {ty:cbox_ty, mut:ast::imm});
+    let llbox = cast_if_we_can(bcx, llbox, cboxptr_ty);
+    check type_is_tup_like(bcx, cboxptr_ty);
 
     // If necessary, copy tydescs describing type parameters into the
     // appropriate slot in the closure.
     let {bcx:bcx, val:ty_params_slot} =
-        GEP_tup_like_1(bcx, closure_ty, closure,
-                       [0, abi::closure_elt_ty_params]);
+        GEP_tup_like_1(bcx, cboxptr_ty, llbox, [0, abi::cbox_elt_ty_params]);
     let off = 0;
-
     for tp in lltyparams {
         let cloned_td = maybe_clone_tydesc(bcx, ck, tp.desc);
         Store(bcx, cloned_td, GEPi(bcx, ty_params_slot, [0, off]));
@@ -254,38 +323,36 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
 
     // Copy expr values into boxed bindings.
     // Silly check
+    let {bcx: bcx, val:bindings_slot} =
+        GEP_tup_like_1(bcx, cboxptr_ty, llbox, [0, abi::cbox_elt_bindings]);
     vec::iteri(bound_values) { |i, bv|
-        let bound = trans::GEP_tup_like_1(bcx, box_ty, box,
-                                          [0, abi::box_rc_field_body,
-                                           abi::closure_elt_bindings,
-                                           i as int]);
-        bcx = bound.bcx;
+        let bound_data = GEPi(bcx, bindings_slot, [0, i as int]);
         alt bv {
           env_expr(e) {
-            bcx = trans::trans_expr_save_in(bcx, e, bound.val);
-            add_clean_temp_mem(bcx, bound.val, bound_tys[i]);
-            temp_cleanups += [bound.val];
+            bcx = trans::trans_expr_save_in(bcx, e, bound_data);
+            add_clean_temp_mem(bcx, bound_data, bound_tys[i]);
+            temp_cleanups += [bound_data];
           }
           env_copy(val, ty, owned.) {
             let val1 = load_if_immediate(bcx, val, ty);
-            bcx = trans::copy_val(bcx, INIT, bound.val, val1, ty);
+            bcx = trans::copy_val(bcx, INIT, bound_data, val1, ty);
           }
           env_copy(val, ty, owned_imm.) {
-            bcx = trans::copy_val(bcx, INIT, bound.val, val, ty);
+            bcx = trans::copy_val(bcx, INIT, bound_data, val, ty);
           }
           env_copy(_, _, temporary.) {
             fail "Cannot capture temporary upvar";
           }
           env_move(val, ty, kind) {
             let src = {bcx:bcx, val:val, kind:kind};
-            bcx = move_val(bcx, INIT, bound.val, src, ty);
+            bcx = move_val(bcx, INIT, bound_data, src, ty);
           }
           env_ref(val, ty, owned.) {
-            Store(bcx, val, bound.val);
+            Store(bcx, val, bound_data);
           }
           env_ref(val, ty, owned_imm.) {
             let addr = do_spill_noroot(bcx, val);
-            Store(bcx, addr, bound.val);
+            Store(bcx, addr, bound_data);
           }
           env_ref(_, _, temporary.) {
             fail "Cannot capture temporary upvar";
@@ -294,7 +361,7 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
     }
     for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
 
-    ret {llbox: box, box_ty: box_ty, bcx: bcx};
+    ret {llbox: llbox, cboxptr_ty: cboxptr_ty, bcx: bcx};
 }
 
 // Given a context and a list of upvars, build a closure. This just
@@ -338,23 +405,21 @@ fn build_closure(bcx0: @block_ctxt,
 // with the upvars and type descriptors.
 fn load_environment(enclosing_cx: @block_ctxt,
                     fcx: @fn_ctxt,
-                    boxed_closure_ty: ty::t,
+                    cboxptr_ty: ty::t,
                     cap_vars: [capture::capture_var],
                     ck: ty::closure_kind) {
     let bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
-
     let ccx = bcx_ccx(bcx);
+
     let sp = bcx.sp;
-    check (type_has_static_size(ccx, boxed_closure_ty));
-    let llty = type_of(ccx, sp, boxed_closure_ty);
+    check (type_has_static_size(ccx, cboxptr_ty));
+    let llty = type_of(ccx, sp, cboxptr_ty);
     let llclosure = PointerCast(bcx, fcx.llenv, llty);
 
     // Populate the type parameters from the environment. We need to
     // do this first because the tydescs are needed to index into
     // the bindings if they are dynamically sized.
-    let lltydescs = GEPi(bcx, llclosure,
-                         [0, abi::box_rc_field_body,
-                          abi::closure_elt_ty_params]);
+    let lltydescs = GEPi(bcx, llclosure, [0, abi::cbox_elt_ty_params]);
     let off = 0;
     for tp in copy enclosing_cx.fcx.lltyparams {
         let tydesc = Load(bcx, GEPi(bcx, lltydescs, [0, off]));
@@ -372,15 +437,15 @@ fn load_environment(enclosing_cx: @block_ctxt,
     }
 
     // Populate the upvars from the environment.
-    let path = [0, abi::box_rc_field_body, abi::closure_elt_bindings];
+    let path = [0, abi::cbox_elt_bindings];
     let i = 0u;
     vec::iter(cap_vars) { |cap_var|
         alt cap_var.mode {
           capture::cap_drop. { /* ignore */ }
           _ {
-            check type_is_tup_like(bcx, boxed_closure_ty);
+            check type_is_tup_like(bcx, cboxptr_ty);
             let upvarptr = GEP_tup_like(
-                bcx, boxed_closure_ty, llclosure, path + [i as int]);
+                bcx, cboxptr_ty, llclosure, path + [i as int]);
             bcx = upvarptr.bcx;
             let llupvarptr = upvarptr.val;
             alt ck {
@@ -415,9 +480,9 @@ fn trans_expr_fn(bcx: @block_ctxt,
     let trans_closure_env = lambda(ck: ty::closure_kind) -> ValueRef {
         let cap_vars = capture::compute_capture_vars(
             ccx.tcx, id, proto, cap_clause);
-        let {llbox, box_ty, bcx} = build_closure(bcx, cap_vars, ck);
+        let {llbox, cboxptr_ty, bcx} = build_closure(bcx, cap_vars, ck);
         trans_closure(sub_cx, sp, decl, body, llfn, no_self, [], id, {|fcx|
-            load_environment(bcx, fcx, box_ty, cap_vars, ck);
+            load_environment(bcx, fcx, cboxptr_ty, cap_vars, ck);
         });
         llbox
     };
@@ -427,7 +492,7 @@ fn trans_expr_fn(bcx: @block_ctxt,
       ast::proto_shared(_) { trans_closure_env(ty::closure_shared) }
       ast::proto_send. { trans_closure_env(ty::closure_send) }
       ast::proto_bare. {
-        let closure = C_null(T_opaque_boxed_closure_ptr(ccx));
+        let closure = C_null(T_opaque_cbox_ptr(ccx));
         trans_closure(sub_cx, sp, decl, body, llfn, no_self, [],
                       id, {|_fcx|});
         closure
@@ -514,7 +579,7 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
     };
 
     // Actually construct the closure
-    let {llbox, box_ty, bcx} = store_environment(
+    let {llbox, cboxptr_ty, bcx} = store_environment(
         bcx, vec::map(lltydescs, {|d| {desc: d, dicts: none}}),
         env_vals + vec::map(bound, {|x| env_expr(x)}),
         ty::closure_shared);
@@ -522,13 +587,27 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
     // Make thunk
     let llthunk =
         trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty_real, args,
-                         box_ty, *param_bounds, target_res);
+                         cboxptr_ty, *param_bounds, target_res);
 
     // Fill the function pair
     fill_fn_pair(bcx, get_dest_addr(dest), llthunk.val, llbox);
     ret bcx;
 }
 
+fn make_null_test(
+    in_bcx: @block_ctxt,
+    ptr: ValueRef,
+    blk: block(@block_ctxt) -> @block_ctxt)
+    -> @block_ctxt {
+    let not_null_bcx = new_sub_block_ctxt(in_bcx, "not null");
+    let next_bcx = new_sub_block_ctxt(in_bcx, "next");
+    let null_test = IsNull(in_bcx, ptr);
+    CondBr(in_bcx, null_test, next_bcx.llbb, not_null_bcx.llbb);
+    let not_null_bcx = blk(not_null_bcx);
+    Br(not_null_bcx, next_bcx.llbb);
+    ret next_bcx;
+}
+
 fn make_fn_glue(
     cx: @block_ctxt,
     v: ValueRef,
@@ -538,52 +617,128 @@ fn make_fn_glue(
     let bcx = cx;
     let tcx = bcx_tcx(cx);
 
-    let fn_env = lambda(blk: block(@block_ctxt, ValueRef) -> @block_ctxt)
-        -> @block_ctxt {
+    let fn_env = lambda(ck: ty::closure_kind) -> @block_ctxt {
         let box_cell_v = GEPi(cx, v, [0, abi::fn_field_box]);
         let box_ptr_v = Load(cx, box_cell_v);
-        let inner_cx = new_sub_block_ctxt(cx, "iter box");
-        let next_cx = new_sub_block_ctxt(cx, "next");
-        let null_test = IsNull(cx, box_ptr_v);
-        CondBr(cx, null_test, next_cx.llbb, inner_cx.llbb);
-        inner_cx = blk(inner_cx, box_cell_v);
-        Br(inner_cx, next_cx.llbb);
-        ret next_cx;
+        make_null_test(cx, box_ptr_v) {|bcx|
+            let closure_ty = ty::mk_opaque_closure_ptr(tcx, ck);
+            glue_fn(bcx, box_cell_v, closure_ty)
+        }
     };
 
     ret alt ty::struct(tcx, t) {
-      ty::ty_native_fn(_, _) | ty::ty_fn({proto: ast::proto_bare., _}) {
-        bcx
-      }
-      ty::ty_fn({proto: ast::proto_block., _}) {
-        bcx
-      }
+      ty::ty_native_fn(_, _) | ty::ty_fn({proto: ast::proto_bare., _}) { bcx }
+      ty::ty_fn({proto: ast::proto_block., _}) { bcx }
       ty::ty_fn({proto: ast::proto_send., _}) {
-        fn_env({ |bcx, box_cell_v|
-            let box_ty = trans_closure::send_opaque_closure_box_ty(tcx);
-            glue_fn(bcx, box_cell_v, box_ty)
-        })
+        fn_env(ty::closure_send)
       }
       ty::ty_fn({proto: ast::proto_shared(_), _}) {
-        fn_env({ |bcx, box_cell_v|
-            let box_ty = trans_closure::shared_opaque_closure_box_ty(tcx);
-            glue_fn(bcx, box_cell_v, box_ty)
-        })
+        fn_env(ty::closure_shared)
       }
       _ { fail "make_fn_glue invoked on non-function type" }
     };
 }
 
-fn call_opaque_closure_glue(bcx: @block_ctxt,
-                            v: ValueRef,     // ptr to an opaque closure
-                            field: int) -> @block_ctxt {
+fn make_opaque_cbox_take_glue(
+    bcx: @block_ctxt,
+    ck: ty::closure_kind,
+    cboxptr: ValueRef)     // ptr to ptr to the opaque closure
+    -> @block_ctxt {
+    // Easy cases:
+    alt ck {
+      ty::closure_block. { ret bcx; }
+      ty::closure_shared. { ret incr_refcnt_of_boxed(bcx, Load(bcx, cboxptr)); }
+      ty::closure_send. { /* hard case: */ }
+    }
+
+    // Hard case, a deep copy:
+    let ccx = bcx_ccx(bcx);
+    let llopaquecboxty = T_opaque_cbox_ptr(ccx);
+    let cbox_in = Load(bcx, cboxptr);
+    make_null_test(bcx, cbox_in) {|bcx|
+        // Load the size from the type descr found in the cbox
+        let cbox_in = PointerCast(bcx, cbox_in, llopaquecboxty);
+        let tydescptr = GEPi(bcx, cbox_in, [0, abi::cbox_elt_tydesc]);
+        let tydesc = Load(bcx, tydescptr);
+        let tydesc = PointerCast(bcx, tydesc, T_ptr(ccx.tydesc_type));
+        let sz = Load(bcx, GEPi(bcx, tydesc, [0, abi::tydesc_field_size]));
+
+        // Allocate memory, update original ptr, and copy existing data
+        let malloc = ccx.upcalls.shared_malloc;
+        let cbox_out = Call(bcx, malloc, [sz, tydesc]);
+        let cbox_out = PointerCast(bcx, cbox_out, llopaquecboxty);
+        let {bcx, val: _} = call_memmove(bcx, cbox_out, cbox_in, sz);
+        Store(bcx, cbox_out, cboxptr);
+
+        // Take the data in the tuple
+        let ti = none;
+        call_tydesc_glue_full(bcx, cbox_out, tydesc,
+                              abi::tydesc_field_take_glue, ti);
+        bcx
+    }
+}
+
+fn make_opaque_cbox_drop_glue(
+    bcx: @block_ctxt,
+    ck: ty::closure_kind,
+    cboxptr: ValueRef)     // ptr to the opaque closure
+    -> @block_ctxt {
+    alt ck {
+      ty::closure_block. { bcx }
+      ty::closure_shared. {
+        decr_refcnt_maybe_free(bcx, Load(bcx, cboxptr),
+                               ty::mk_opaque_closure_ptr(bcx_tcx(bcx), ck))
+      }
+      ty::closure_send. {
+        free_ty(bcx, Load(bcx, cboxptr),
+                ty::mk_opaque_closure_ptr(bcx_tcx(bcx), ck))
+      }
+    }
+}
+
+fn make_opaque_cbox_free_glue(
+    bcx: @block_ctxt,
+    ck: ty::closure_kind,
+    cbox: ValueRef)     // ptr to the opaque closure
+    -> @block_ctxt {
+    alt ck {
+      ty::closure_block. { ret bcx; }
+      ty::closure_shared. | ty::closure_send. { /* hard cases: */ }
+    }
+
     let ccx = bcx_ccx(bcx);
-    let v = PointerCast(bcx, v, T_ptr(T_opaque_closure(ccx)));
-    let tydescptr = GEPi(bcx, v, [0, abi::closure_elt_tydesc]);
-    let tydesc = Load(bcx, tydescptr);
-    let ti = none;
-    call_tydesc_glue_full(bcx, v, tydesc, field, ti);
-    ret bcx;
+    make_null_test(bcx, cbox) {|bcx|
+        // Load the type descr found in the cbox
+        let lltydescty = T_ptr(ccx.tydesc_type);
+        let cbox = PointerCast(bcx, cbox, T_opaque_cbox_ptr(ccx));
+        let tydescptr = GEPi(bcx, cbox, [0, abi::cbox_elt_tydesc]);
+        let tydesc = Load(bcx, tydescptr);
+        let tydesc = PointerCast(bcx, tydesc, lltydescty);
+
+        // Null out the type descr in the cbox.  This is subtle:
+        // we will be freeing the data in the cbox, and we may need the
+        // information in the type descr to guide the GEP_tup_like process
+        // etc if generic types are involved.  So we null it out at first
+        // then free it manually below.
+        Store(bcx, C_null(lltydescty), tydescptr);
+
+        // Drop the tuple data then free the descriptor
+        let ti = none;
+        call_tydesc_glue_full(bcx, cbox, tydesc,
+                              abi::tydesc_field_drop_glue, ti);
+
+        // Free the ty descr (if necc) and the box itself
+        alt ck {
+          ty::closure_block. { fail "Impossible."; }
+          ty::closure_shared. {
+            trans_free_if_not_gc(bcx, cbox)
+          }
+          ty::closure_send. {
+            let bcx = trans_shared_free(bcx, tydesc);
+            trans_shared_free(bcx, cbox)
+          }
+        }
+    }
 }
 
 // pth is cx.path
@@ -592,7 +747,7 @@ fn trans_bind_thunk(cx: @local_ctxt,
                     incoming_fty: ty::t,
                     outgoing_fty: ty::t,
                     args: [option::t<@ast::expr>],
-                    boxed_closure_ty: ty::t,
+                    cboxptr_ty: ty::t,
                     param_bounds: [ty::param_bounds],
                     target_fn: option::t<ValueRef>)
     -> {val: ValueRef, ty: TypeRef} {
@@ -648,9 +803,9 @@ fn trans_bind_thunk(cx: @local_ctxt,
     // to the original function.  So, let's create one of those:
 
     // The llenv pointer needs to be the correct size.  That size is
-    // 'boxed_closure_ty', which was determined by trans_bind.
-    check (type_has_static_size(ccx, boxed_closure_ty));
-    let llclosure_ptr_ty = type_of(ccx, sp, boxed_closure_ty);
+    // 'cboxptr_ty', which was determined by trans_bind.
+    check type_has_static_size(ccx, cboxptr_ty);
+    let llclosure_ptr_ty = type_of(ccx, sp, cboxptr_ty);
     let llclosure = PointerCast(l_bcx, fcx.llenv, llclosure_ptr_ty);
 
     // "target", in this context, means the function that's having some of its
@@ -660,15 +815,14 @@ fn trans_bind_thunk(cx: @local_ctxt,
     // target function lives in the first binding spot.
     let (lltargetfn, lltargetenv, starting_idx) = alt target_fn {
       some(fptr) {
-        (fptr, llvm::LLVMGetUndef(T_opaque_boxed_closure_ptr(ccx)), 0)
+        (fptr, llvm::LLVMGetUndef(T_opaque_cbox_ptr(ccx)), 0)
       }
       none. {
         // Silly check
-        check type_is_tup_like(bcx, boxed_closure_ty);
+        check type_is_tup_like(bcx, cboxptr_ty);
         let {bcx: cx, val: pair} =
-            GEP_tup_like(bcx, boxed_closure_ty, llclosure,
-                         [0, abi::box_rc_field_body,
-                          abi::closure_elt_bindings, 0]);
+            GEP_tup_like(bcx, cboxptr_ty, llclosure,
+                         [0, abi::cbox_elt_bindings, 0]);
         let lltargetenv =
             Load(cx, GEPi(cx, pair, [0, abi::fn_field_box]));
         let lltargetfn = Load
@@ -702,10 +856,9 @@ fn trans_bind_thunk(cx: @local_ctxt,
     let llargs: [ValueRef] = [llretptr, lltargetenv];
 
     // Copy in the type parameters.
-    check type_is_tup_like(l_bcx, boxed_closure_ty);
+    check type_is_tup_like(l_bcx, cboxptr_ty);
     let {bcx: l_bcx, val: param_record} =
-        GEP_tup_like(l_bcx, boxed_closure_ty, llclosure,
-                     [0, abi::box_rc_field_body, abi::closure_elt_ty_params]);
+        GEP_tup_like(l_bcx, cboxptr_ty, llclosure, [0, abi::cbox_elt_ty_params]);
     let off = 0;
     for param in param_bounds {
         let dsc = Load(l_bcx, GEPi(l_bcx, param_record, [0, off])),
@@ -743,11 +896,10 @@ fn trans_bind_thunk(cx: @local_ctxt,
           // closure.
           some(e) {
             // Silly check
-            check type_is_tup_like(bcx, boxed_closure_ty);
+            check type_is_tup_like(bcx, cboxptr_ty);
             let bound_arg =
-                GEP_tup_like(bcx, boxed_closure_ty, llclosure,
-                             [0, abi::box_rc_field_body,
-                              abi::closure_elt_bindings, b]);
+                GEP_tup_like(bcx, cboxptr_ty, llclosure,
+                             [0, abi::cbox_elt_bindings, b]);
             bcx = bound_arg.bcx;
             let val = bound_arg.val;
             if out_arg.mode == ast::by_val { val = Load(bcx, val); }
index 3e3df30c9f3dbffed995872882a8019e577dff9c..8b99efc337b133e09fdbf67f1e33d9b738b83238 100644 (file)
@@ -542,7 +542,7 @@ fn T_fn(inputs: [TypeRef], output: TypeRef) -> TypeRef unsafe {
 }
 
 fn T_fn_pair(cx: @crate_ctxt, tfn: TypeRef) -> TypeRef {
-    ret T_struct([T_ptr(tfn), T_opaque_boxed_closure_ptr(cx)]);
+    ret T_struct([T_ptr(tfn), T_opaque_cbox_ptr(cx)]);
 }
 
 fn T_ptr(t: TypeRef) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); }
@@ -698,34 +698,14 @@ fn T_typaram(tn: type_names) -> TypeRef {
 
 fn T_typaram_ptr(tn: type_names) -> TypeRef { ret T_ptr(T_typaram(tn)); }
 
-fn T_closure(cx: @crate_ctxt,
-             llbindings_ty: TypeRef,
-             n_ty_params: uint) -> TypeRef {
-    ret T_struct([T_ptr(cx.tydesc_type),
-                  T_captured_tydescs(cx, n_ty_params),
-                  llbindings_ty])
-}
-
-fn T_opaque_closure(cx: @crate_ctxt) -> TypeRef {
-    let s = "closure";
-    if cx.tn.name_has_type(s) { ret cx.tn.get_type(s); }
-    let t = T_closure(cx, T_nil(), 0u);
-    cx.tn.associate(s, t);
-    ret t;
-}
-
-fn T_boxed_closure_ptr(cx: @crate_ctxt, llbindings_ty: TypeRef,
-                     n_ty_params: uint) -> TypeRef {
-    // NB: keep this in sync with code in trans_bind; we're making
-    // an LLVM typeref structure that has the same "shape" as the ty::t
-    // it constructs.
-    ret T_ptr(T_box(cx, T_closure(cx, llbindings_ty, n_ty_params)));
-}
-
-fn T_opaque_boxed_closure_ptr(cx: @crate_ctxt) -> TypeRef {
-    let s = "*closure";
+fn T_opaque_cbox_ptr(cx: @crate_ctxt) -> TypeRef {
+    let s = "*cbox";
     if cx.tn.name_has_type(s) { ret cx.tn.get_type(s); }
-    let t = T_boxed_closure_ptr(cx, T_nil(), 0u);
+    let t = T_ptr(T_struct([cx.int_type,
+                            T_ptr(cx.tydesc_type),
+                            T_i8() /* represents closed over tydescs
+                            and data go here; see trans_closure.rs*/
+                           ]));
     cx.tn.associate(s, t);
     ret t;
 }
index 77422065f1148de2493285e0f344d1921e6f0483..284cef0f289d33ef593f23fbf5c1eddce2327728 100644 (file)
@@ -58,7 +58,7 @@ fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
     let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
                                     T_ptr(type_of_or_i8(bcx, basety)), tz,
                                     tr, base);
-    rslt(bcx, PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx))))
+    rslt(bcx, PointerCast(bcx, val, T_opaque_cbox_ptr(bcx_ccx(bcx))))
 }
 
 fn trans_static_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
index bcf0cfb69ea0bd1b0524176ab0042646c8328f4f..4c7c8942f289922b1ef5abcdad2ec1570ea2ae09 100644 (file)
@@ -84,7 +84,7 @@
 export mk_uint;
 export mk_uniq;
 export mk_var;
-export mk_opaque_closure;
+export mk_opaque_closure_ptr;
 export mk_named;
 export gen_ty;
 export mode;
 export ty_bot;
 export ty_box;
 export ty_constr;
-export ty_opaque_closure;
+export ty_opaque_closure_ptr;
 export ty_constr_arg;
 export ty_float;
 export ty_fn, fn_ty;
 export type_err;
 export type_err_to_str;
 export type_has_dynamic_size;
-export type_has_opaque_size;
 export type_needs_drop;
 export type_is_bool;
 export type_is_bot;
     ty_send_type; // type_desc* that has been cloned into exchange heap
     ty_native(def_id);
     ty_constr(t, [@type_constr]);
-    ty_opaque_closure; // type of a captured environment.
+    ty_opaque_closure_ptr(closure_kind); // ptr to env for fn, fn@, fn~
     ty_named(t, @str);
 }
 
@@ -368,9 +367,7 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind {
 
 const idx_bot: uint = 19u;
 
-const idx_opaque_closure: uint = 20u;
-
-const idx_first_others: uint = 21u;
+const idx_first_others: uint = 20u;
 
 type type_store = interner::interner<@raw_t>;
 
@@ -400,7 +397,6 @@ fn populate_type_store(cx: ctxt) {
     intern(cx, ty_type);
     intern(cx, ty_send_type);
     intern(cx, ty_bot);
-    intern(cx, ty_opaque_closure);
     assert (vec::len(cx.ts.vect) == idx_first_others);
 }
 
@@ -471,7 +467,8 @@ fn derive_flags_sig(cx: ctxt, &has_params: bool, &has_vars: bool,
     }
     alt st {
       ty_nil. | ty_bot. | ty_bool. | ty_int(_) | ty_float(_) | ty_uint(_) |
-      ty_str. | ty_send_type. | ty_type. | ty_native(_) | ty_opaque_closure. {
+      ty_str. | ty_send_type. | ty_type. | ty_native(_) |
+      ty_opaque_closure_ptr(_) {
         /* no-op */
       }
       ty_param(_, _) { has_params = true; }
@@ -636,8 +633,8 @@ fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
 
 fn mk_native(cx: ctxt, did: def_id) -> t { ret gen_ty(cx, ty_native(did)); }
 
-fn mk_opaque_closure(_cx: ctxt) -> t {
-    ret idx_opaque_closure;
+fn mk_opaque_closure_ptr(cx: ctxt, ck: closure_kind) -> t {
+    ret gen_ty(cx, ty_opaque_closure_ptr(ck));
 }
 
 fn mk_named(cx: ctxt, base: t, name: @str) -> t {
@@ -685,7 +682,8 @@ fn mk_named(cx: ctxt, base: t, name: @str) -> t {
 fn walk_ty(cx: ctxt, walker: ty_walk, ty: t) {
     alt struct(cx, ty) {
       ty_nil. | ty_bot. | ty_bool. | ty_int(_) | ty_uint(_) | ty_float(_) |
-      ty_str. | ty_send_type. | ty_type. | ty_native(_) | ty_opaque_closure. {
+      ty_str. | ty_send_type. | ty_type. | ty_native(_) |
+      ty_opaque_closure_ptr(_) {
         /* no-op */
       }
       ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, walker, tm.ty); }
@@ -739,7 +737,8 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
     }
     alt interner::get(*cx.ts, ty).struct {
       ty_nil. | ty_bot. | ty_bool. | ty_int(_) | ty_uint(_) | ty_float(_) |
-      ty_str. | ty_send_type. | ty_type. | ty_native(_) | ty_opaque_closure. {
+      ty_str. | ty_send_type. | ty_type. | ty_native(_) |
+      ty_opaque_closure_ptr(_) {
         /* no-op */
       }
       ty_box(tm) {
@@ -881,6 +880,7 @@ fn sequence_element_type(cx: ctxt, ty: t) -> t {
 pure fn type_is_tup_like(cx: ctxt, ty: t) -> bool {
     let sty = struct(cx, ty);
     alt sty {
+      ty_ptr(_) | ty_uniq(_) |
       ty_box(_) | ty_rec(_) | ty_tup(_) | ty_tag(_,_) { true }
       _ { false }
     }
@@ -1058,7 +1058,9 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
       // anything about its fields.
       ty_obj(_) { kind_copyable }
       ty_fn(f) { proto_kind(f.proto) }
-      ty_opaque_closure. { kind_noncopyable }
+      ty_opaque_closure_ptr(closure_block.) { kind_noncopyable }
+      ty_opaque_closure_ptr(closure_shared.) { kind_copyable }
+      ty_opaque_closure_ptr(closure_send.) { kind_sendable }
       // Those with refcounts-to-inner raise pinned to shared,
       // lower unique to shared. Therefore just set result to shared.
       ty_box(_) | ty_iface(_, _) { kind_copyable }
@@ -1141,15 +1143,6 @@ fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) ->
     }
 }
 
-pure fn type_has_opaque_size(cx: ctxt, ty: t) -> bool unchecked {
-    type_structurally_contains(cx, ty, fn (sty: sty) -> bool {
-        alt sty {
-          ty_opaque_closure. { true}
-          _ { false }
-        }
-    })
-}
-
 pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked {
 
     /* type_structurally_contains can't be declared pure
@@ -1162,7 +1155,7 @@ fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) ->
     */
     type_structurally_contains(cx, ty, fn (sty: sty) -> bool {
         alt sty {
-          ty_opaque_closure. | ty_param(_, _) { true }
+          ty_param(_, _) { true }
           _ { false }
         }
     })
@@ -1424,13 +1417,15 @@ fn hash_fn(id: uint, args: [arg], rty: t) -> uint {
       }
       ty_uniq(mt) { ret hash_subty(37u, mt.ty); }
       ty_send_type. { ret 38u; }
-      ty_opaque_closure. { ret 39u; }
-      ty_named(t, name) { (str::hash(*name) << 5u) + hash_subty(40u, t) }
+      ty_named(t, name) { (str::hash(*name) << 5u) + hash_subty(39u, t) }
       ty_iface(did, tys) {
-        let h = hash_def(41u, did);
-        for typ: t in tys { h += (h << 5u) + typ; }
+        let h = hash_def(40u, did);
+        for typ: t in tys { h = hash_subty(h, typ); }
         ret h;
       }
+      ty_opaque_closure_ptr(closure_block.) { ret 41u; }
+      ty_opaque_closure_ptr(closure_shared.) { ret 42u; }
+      ty_opaque_closure_ptr(closure_send.) { ret 43u; }
     }
 }