From: Niko Matsakis Date: Fri, 6 Jan 2012 00:19:12 +0000 (-0800) Subject: rejigger impl to have an opaque closure ptr rather than X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=8e89df69de47a4f944f5c3fc249a88c5934864b2;p=rust.git rejigger impl to have an opaque closure ptr rather than opaque closure --- diff --git a/src/comp/back/abi.rs b/src/comp/back/abi.rs index e5d93baa9d3..8e317ce0e9e 100644 --- a/src/comp/back/abi.rs +++ b/src/comp/back/abi.rs @@ -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; @@ -72,9 +72,13 @@ 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; diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs index e339f4bc92e..ae65c284fc2 100644 --- a/src/comp/metadata/tydecode.rs +++ b/src/comp/metadata/tydecode.rs @@ -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 == ':'); diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs index 2ba572154c5..f5c4c91d0ac 100644 --- a/src/comp/metadata/tyencode.rs +++ b/src/comp/metadata/tyencode.rs @@ -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); diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs index f78e0ffef85..43afb88361b 100644 --- a/src/comp/middle/shape.rs +++ b/src/comp/middle/shape.rs @@ -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]; } } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 03adeb6843d..fa4a1a72969 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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) -> 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}; 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); } diff --git a/src/comp/middle/trans_closure.rs b/src/comp/middle/trans_closure.rs index 831a5b4e41e..57791f17ee0 100644 --- a/src/comp/middle/trans_closure.rs +++ b/src/comp/middle/trans_closure.rs @@ -31,28 +31,22 @@ // 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 @@ -63,6 +57,53 @@ // 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 { @@ -79,16 +120,24 @@ 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) -> {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); } diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 3e3df30c9f3..8b99efc337b 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -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; } diff --git a/src/comp/middle/trans_impl.rs b/src/comp/middle/trans_impl.rs index 77422065f11..284cef0f289 100644 --- a/src/comp/middle/trans_impl.rs +++ b/src/comp/middle/trans_impl.rs @@ -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, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index bcf0cfb69ea..4c7c8942f28 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -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; @@ -111,7 +111,7 @@ 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; @@ -149,7 +149,6 @@ 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; @@ -276,7 +275,7 @@ 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; } } }