]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/glue.rs
d3f5b9844c930f6c1607c2637a976e063ad973da
[rust.git] / src / librustc / middle / trans / glue.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //!
12 //
13 // Code relating to taking, dropping, etc as well as type descriptors.
14
15
16 use back::abi;
17 use back::link::*;
18 use driver::session;
19 use lib;
20 use lib::llvm::{llvm, ValueRef, True};
21 use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem};
22 use middle::trans::adt;
23 use middle::trans::base::*;
24 use middle::trans::callee;
25 use middle::trans::closure;
26 use middle::trans::common::*;
27 use middle::trans::build::*;
28 use middle::trans::expr;
29 use middle::trans::machine::*;
30 use middle::trans::reflect;
31 use middle::trans::tvec;
32 use middle::trans::type_of::type_of;
33 use middle::trans::uniq;
34 use middle::ty;
35 use util::ppaux;
36 use util::ppaux::ty_to_short_str;
37
38 use middle::trans::type_::Type;
39
40 use std::io;
41 use std::libc::c_uint;
42 use std::str;
43 use syntax::ast;
44
45 pub fn trans_free(cx: block, v: ValueRef) -> block {
46     let _icx = push_ctxt("trans_free");
47     callee::trans_lang_call(cx,
48         langcall(cx, None, "", FreeFnLangItem),
49         [PointerCast(cx, v, Type::i8p())],
50         Some(expr::Ignore)).bcx
51 }
52
53 pub fn trans_exchange_free(cx: block, v: ValueRef) -> block {
54     let _icx = push_ctxt("trans_exchange_free");
55     callee::trans_lang_call(cx,
56         langcall(cx, None, "", ExchangeFreeFnLangItem),
57         [PointerCast(cx, v, Type::i8p())],
58         Some(expr::Ignore)).bcx
59 }
60
61 pub fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block {
62     // NB: v is an *alias* of type t here, not a direct value.
63     let _icx = push_ctxt("take_ty");
64     if ty::type_needs_drop(cx.tcx(), t) {
65         return call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
66     }
67     return cx;
68 }
69
70 pub fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block {
71     // NB: v is an *alias* of type t here, not a direct value.
72     let _icx = push_ctxt("drop_ty");
73     if ty::type_needs_drop(cx.tcx(), t) {
74         return call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
75     }
76     return cx;
77 }
78
79 pub fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
80     let _icx = push_ctxt("drop_ty_immediate");
81     match ty::get(t).sty {
82         ty::ty_uniq(_)
83       | ty::ty_evec(_, ty::vstore_uniq)
84       | ty::ty_estr(ty::vstore_uniq) => {
85         free_ty_immediate(bcx, v, t)
86       }
87         ty::ty_box(_) | ty::ty_opaque_box
88       | ty::ty_evec(_, ty::vstore_box)
89       | ty::ty_estr(ty::vstore_box) => {
90         decr_refcnt_maybe_free(bcx, v, None, t)
91       }
92       _ => bcx.tcx().sess.bug("drop_ty_immediate: non-box ty")
93     }
94 }
95
96 pub fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block {
97     // NB: v is an *alias* of type t here, not a direct value.
98     let _icx = push_ctxt("free_ty");
99     if ty::type_needs_drop(cx.tcx(), t) {
100         return call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue);
101     }
102     return cx;
103 }
104
105 pub fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
106     let _icx = push_ctxt("free_ty_immediate");
107     match ty::get(t).sty {
108       ty::ty_uniq(_) |
109       ty::ty_evec(_, ty::vstore_uniq) |
110       ty::ty_estr(ty::vstore_uniq) |
111       ty::ty_box(_) | ty::ty_opaque_box |
112       ty::ty_evec(_, ty::vstore_box) |
113       ty::ty_estr(ty::vstore_box) |
114       ty::ty_opaque_closure_ptr(_) => {
115         let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
116         Store(bcx, v, vp);
117         free_ty(bcx, vp, t)
118       }
119       _ => bcx.tcx().sess.bug("free_ty_immediate: non-box ty")
120     }
121 }
122
123 pub fn lazily_emit_all_tydesc_glue(ccx: @mut CrateContext,
124                                    static_ti: @mut tydesc_info) {
125     lazily_emit_tydesc_glue(ccx, abi::tydesc_field_take_glue, static_ti);
126     lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti);
127     lazily_emit_tydesc_glue(ccx, abi::tydesc_field_free_glue, static_ti);
128     lazily_emit_tydesc_glue(ccx, abi::tydesc_field_visit_glue, static_ti);
129 }
130
131 pub fn simplified_glue_type(tcx: ty::ctxt, field: uint, t: ty::t) -> ty::t {
132     if (field == abi::tydesc_field_take_glue ||
133         field == abi::tydesc_field_drop_glue ||
134         field == abi::tydesc_field_free_glue) &&
135         ! ty::type_needs_drop(tcx, t) {
136           return ty::mk_u32();
137     }
138
139     if field == abi::tydesc_field_take_glue {
140         match ty::get(t).sty {
141           ty::ty_unboxed_vec(*) => { return ty::mk_u32(); }
142           _ => ()
143         }
144     }
145
146     if field == abi::tydesc_field_take_glue &&
147         ty::type_is_boxed(t) {
148           return ty::mk_imm_box(tcx, ty::mk_u32());
149     }
150
151     if field == abi::tydesc_field_free_glue {
152         match ty::get(t).sty {
153           ty::ty_bare_fn(*) |
154           ty::ty_closure(*) |
155           ty::ty_box(*) |
156           ty::ty_opaque_box |
157           ty::ty_uniq(*) |
158           ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) |
159           ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) |
160           ty::ty_opaque_closure_ptr(*) => (),
161           _ => { return ty::mk_u32(); }
162         }
163     }
164
165     if (field == abi::tydesc_field_free_glue ||
166         field == abi::tydesc_field_drop_glue) {
167         match ty::get(t).sty {
168           ty::ty_box(mt) |
169           ty::ty_evec(mt, ty::vstore_box)
170           if ! ty::type_needs_drop(tcx, mt.ty) =>
171           return ty::mk_imm_box(tcx, ty::mk_u32()),
172
173           ty::ty_uniq(mt) |
174           ty::ty_evec(mt, ty::vstore_uniq)
175           if ! ty::type_needs_drop(tcx, mt.ty) =>
176           return ty::mk_imm_uniq(tcx, ty::mk_u32()),
177
178           _ => ()
179         }
180     }
181
182     return t;
183 }
184
185 pub fn lazily_emit_simplified_tydesc_glue(ccx: @mut CrateContext,
186                                           field: uint,
187                                           ti: &mut tydesc_info) -> bool {
188     let _icx = push_ctxt("lazily_emit_simplified_tydesc_glue");
189     let simpl = simplified_glue_type(ccx.tcx, field, ti.ty);
190     if simpl != ti.ty {
191         let simpl_ti = get_tydesc(ccx, simpl);
192         lazily_emit_tydesc_glue(ccx, field, simpl_ti);
193         {
194             if field == abi::tydesc_field_take_glue {
195                 ti.take_glue = simpl_ti.take_glue;
196             } else if field == abi::tydesc_field_drop_glue {
197                 ti.drop_glue = simpl_ti.drop_glue;
198             } else if field == abi::tydesc_field_free_glue {
199                 ti.free_glue = simpl_ti.free_glue;
200             } else if field == abi::tydesc_field_visit_glue {
201                 ti.visit_glue = simpl_ti.visit_glue;
202             }
203         }
204         return true;
205     }
206     return false;
207 }
208
209
210 pub fn lazily_emit_tydesc_glue(ccx: @mut CrateContext,
211                                field: uint,
212                                ti: @mut tydesc_info) {
213     let _icx = push_ctxt("lazily_emit_tydesc_glue");
214     let llfnty = Type::glue_fn(type_of::type_of(ccx, ti.ty).ptr_to());
215
216     if lazily_emit_simplified_tydesc_glue(ccx, field, ti) {
217         return;
218     }
219
220     if field == abi::tydesc_field_take_glue {
221         match ti.take_glue {
222           Some(_) => (),
223           None => {
224             debug!("+++ lazily_emit_tydesc_glue TAKE %s",
225                    ppaux::ty_to_str(ccx.tcx, ti.ty));
226             let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "take");
227             ti.take_glue = Some(glue_fn);
228             make_generic_glue(ccx, ti.ty, glue_fn, make_take_glue, "take");
229             debug!("--- lazily_emit_tydesc_glue TAKE %s",
230                    ppaux::ty_to_str(ccx.tcx, ti.ty));
231           }
232         }
233     } else if field == abi::tydesc_field_drop_glue {
234         match ti.drop_glue {
235           Some(_) => (),
236           None => {
237             debug!("+++ lazily_emit_tydesc_glue DROP %s",
238                    ppaux::ty_to_str(ccx.tcx, ti.ty));
239             let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "drop");
240             ti.drop_glue = Some(glue_fn);
241             make_generic_glue(ccx, ti.ty, glue_fn, make_drop_glue, "drop");
242             debug!("--- lazily_emit_tydesc_glue DROP %s",
243                    ppaux::ty_to_str(ccx.tcx, ti.ty));
244           }
245         }
246     } else if field == abi::tydesc_field_free_glue {
247         match ti.free_glue {
248           Some(_) => (),
249           None => {
250             debug!("+++ lazily_emit_tydesc_glue FREE %s",
251                    ppaux::ty_to_str(ccx.tcx, ti.ty));
252             let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "free");
253             ti.free_glue = Some(glue_fn);
254             make_generic_glue(ccx, ti.ty, glue_fn, make_free_glue, "free");
255             debug!("--- lazily_emit_tydesc_glue FREE %s",
256                    ppaux::ty_to_str(ccx.tcx, ti.ty));
257           }
258         }
259     } else if field == abi::tydesc_field_visit_glue {
260         match ti.visit_glue {
261           Some(_) => (),
262           None => {
263             debug!("+++ lazily_emit_tydesc_glue VISIT %s",
264                    ppaux::ty_to_str(ccx.tcx, ti.ty));
265             let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "visit");
266             ti.visit_glue = Some(glue_fn);
267             make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit");
268             debug!("--- lazily_emit_tydesc_glue VISIT %s",
269                    ppaux::ty_to_str(ccx.tcx, ti.ty));
270           }
271         }
272     }
273 }
274
275 // See [Note-arg-mode]
276 pub fn call_tydesc_glue_full(bcx: block,
277                              v: ValueRef,
278                              tydesc: ValueRef,
279                              field: uint,
280                              static_ti: Option<@mut tydesc_info>) {
281     let _icx = push_ctxt("call_tydesc_glue_full");
282     let ccx = bcx.ccx();
283     // NB: Don't short-circuit even if this block is unreachable because
284     // GC-based cleanup needs to the see that the roots are live.
285     let no_lpads =
286         ccx.sess.opts.debugging_opts & session::no_landing_pads != 0;
287     if bcx.unreachable && !no_lpads { return; }
288
289     let static_glue_fn = match static_ti {
290       None => None,
291       Some(sti) => {
292         lazily_emit_tydesc_glue(ccx, field, sti);
293         if field == abi::tydesc_field_take_glue {
294             sti.take_glue
295         } else if field == abi::tydesc_field_drop_glue {
296             sti.drop_glue
297         } else if field == abi::tydesc_field_free_glue {
298             sti.free_glue
299         } else if field == abi::tydesc_field_visit_glue {
300             sti.visit_glue
301         } else {
302             None
303         }
304       }
305     };
306
307     // When static type info is available, avoid casting parameter unless the
308     // glue is using a simplified type, because the function already has the
309     // right type. Otherwise cast to generic pointer.
310     let llrawptr = if static_ti.is_none() || static_glue_fn.is_none() {
311         PointerCast(bcx, v, Type::i8p())
312     } else {
313         let ty = static_ti.get().ty;
314         let simpl = simplified_glue_type(ccx.tcx, field, ty);
315         if simpl != ty {
316             PointerCast(bcx, v, type_of(ccx, simpl).ptr_to())
317         } else {
318             v
319         }
320     };
321
322     let llfn = {
323         match static_glue_fn {
324           None => {
325             // Select out the glue function to call from the tydesc
326             let llfnptr = GEPi(bcx, tydesc, [0u, field]);
327             Load(bcx, llfnptr)
328           }
329           Some(sgf) => sgf
330         }
331     };
332
333     Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr]);
334 }
335
336 // See [Note-arg-mode]
337 pub fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: uint)
338     -> block {
339     let _icx = push_ctxt("call_tydesc_glue");
340     let ti = get_tydesc(cx.ccx(), t);
341     call_tydesc_glue_full(cx, v, ti.tydesc, field, Some(ti));
342     return cx;
343 }
344
345 pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
346     let _icx = push_ctxt("make_visit_glue");
347     do with_scope(bcx, None, "visitor cleanup") |bcx| {
348         let mut bcx = bcx;
349         let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx()){
350             Ok(pair) => pair,
351             Err(s) => {
352                 bcx.tcx().sess.fatal(s);
353             }
354         };
355         let v = PointerCast(bcx, v, type_of::type_of(bcx.ccx(), object_ty).ptr_to());
356         bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id);
357         // The visitor is a boxed object and needs to be dropped
358         add_clean(bcx, v, object_ty);
359         bcx
360     }
361 }
362
363 pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
364     // NB: v0 is an *alias* of type t here, not a direct value.
365     let _icx = push_ctxt("make_free_glue");
366     match ty::get(t).sty {
367       ty::ty_box(body_mt) => {
368         let v = Load(bcx, v);
369         let body = GEPi(bcx, v, [0u, abi::box_field_body]);
370         let bcx = drop_ty(bcx, body, body_mt.ty);
371         trans_free(bcx, v)
372       }
373       ty::ty_opaque_box => {
374         let v = Load(bcx, v);
375         let td = Load(bcx, GEPi(bcx, v, [0u, abi::box_field_tydesc]));
376         let valptr = GEPi(bcx, v, [0u, abi::box_field_body]);
377         // Generate code that, dynamically, indexes into the
378         // tydesc and calls the drop glue that got set dynamically
379         call_tydesc_glue_full(bcx, valptr, td, abi::tydesc_field_drop_glue,
380                               None);
381         trans_free(bcx, v)
382       }
383       ty::ty_uniq(*) => {
384         uniq::make_free_glue(bcx, v, t)
385       }
386       ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) |
387       ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => {
388         make_free_glue(bcx, v, tvec::expand_boxed_vec_ty(bcx.tcx(), t))
389       }
390       ty::ty_closure(_) => {
391         closure::make_closure_glue(bcx, v, t, free_ty)
392       }
393       ty::ty_opaque_closure_ptr(ck) => {
394         closure::make_opaque_cbox_free_glue(bcx, ck, v)
395       }
396       _ => bcx
397     }
398 }
399
400 pub fn trans_struct_drop_flag(bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id,
401                               class_did: ast::def_id, substs: &ty::substs) -> block {
402     let repr = adt::represent_type(bcx.ccx(), t);
403     let drop_flag = adt::trans_drop_flag_ptr(bcx, repr, v0);
404     do with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) |cx| {
405         let mut bcx = cx;
406
407         // Find and call the actual destructor
408         let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did,
409                                      class_did, substs.tps.clone());
410
411         // The second argument is the "self" argument for drop
412         let params = unsafe {
413             let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
414             ty.element_type().func_params()
415         };
416
417         // Class dtors have no explicit args, so the params should
418         // just consist of the environment (self)
419         assert_eq!(params.len(), 1);
420
421         let self_arg = PointerCast(bcx, v0, params[0]);
422         let args = ~[self_arg];
423
424         Call(bcx, dtor_addr, args);
425
426         // Drop the fields
427         let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
428         for field_tys.iter().enumerate().advance |(i, fld)| {
429             let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i);
430             bcx = drop_ty(bcx, llfld_a, fld.mt.ty);
431         }
432
433         Store(bcx, C_u8(0), drop_flag);
434         bcx
435     }
436 }
437
438 pub fn trans_struct_drop(mut bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id,
439                          class_did: ast::def_id, substs: &ty::substs) -> block {
440     let repr = adt::represent_type(bcx.ccx(), t);
441
442     // Find and call the actual destructor
443     let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did,
444                                  class_did, substs.tps.clone());
445
446     // The second argument is the "self" argument for drop
447     let params = unsafe {
448         let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
449         ty.element_type().func_params()
450     };
451
452     // Class dtors have no explicit args, so the params should
453     // just consist of the environment (self)
454     assert_eq!(params.len(), 1);
455
456     let self_arg = PointerCast(bcx, v0, params[0]);
457     let args = ~[self_arg];
458
459     Call(bcx, dtor_addr, args);
460
461     // Drop the fields
462     let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
463     for field_tys.iter().enumerate().advance |(i, fld)| {
464         let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i);
465         bcx = drop_ty(bcx, llfld_a, fld.mt.ty);
466     }
467
468     bcx
469 }
470
471 pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) -> block {
472     // NB: v0 is an *alias* of type t here, not a direct value.
473     let _icx = push_ctxt("make_drop_glue");
474     let ccx = bcx.ccx();
475     match ty::get(t).sty {
476       ty::ty_box(_) | ty::ty_opaque_box |
477       ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) => {
478         decr_refcnt_maybe_free(bcx, Load(bcx, v0), Some(v0), t)
479       }
480       ty::ty_uniq(_) |
481       ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) => {
482         free_ty(bcx, v0, t)
483       }
484       ty::ty_unboxed_vec(_) => {
485         tvec::make_drop_glue_unboxed(bcx, v0, t)
486       }
487       ty::ty_struct(did, ref substs) => {
488         let tcx = bcx.tcx();
489         match ty::ty_dtor(tcx, did) {
490           ty::TraitDtor(dtor, true) => {
491             trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
492           }
493           ty::TraitDtor(dtor, false) => {
494             trans_struct_drop(bcx, t, v0, dtor, did, substs)
495           }
496           ty::NoDtor => {
497             // No dtor? Just the default case
498             iter_structural_ty(bcx, v0, t, drop_ty)
499           }
500         }
501       }
502       ty::ty_closure(_) => {
503         closure::make_closure_glue(bcx, v0, t, drop_ty)
504       }
505       ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
506           let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]);
507           let llbox = Load(bcx, llbox_ptr);
508           decr_refcnt_maybe_free(bcx, llbox, Some(llbox_ptr),
509                                  ty::mk_opaque_box(ccx.tcx))
510       }
511       ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
512           let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
513           // Only drop the value when it is non-null
514           do with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue))) |bcx| {
515               let llvtable = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
516
517               // Cast the vtable to a pointer to a pointer to a tydesc.
518               let llvtable = PointerCast(bcx, llvtable,
519                                          ccx.tydesc_type.ptr_to().ptr_to());
520               let lltydesc = Load(bcx, llvtable);
521               call_tydesc_glue_full(bcx,
522                                     lluniquevalue,
523                                     lltydesc,
524                                     abi::tydesc_field_free_glue,
525                                     None);
526               bcx
527           }
528       }
529       ty::ty_opaque_closure_ptr(ck) => {
530         closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
531       }
532       _ => {
533         if ty::type_needs_drop(ccx.tcx, t) &&
534             ty::type_is_structural(t) {
535             iter_structural_ty(bcx, v0, t, drop_ty)
536         } else { bcx }
537       }
538     }
539 }
540
541 // box_ptr_ptr is optional, it is constructed if not supplied.
542 pub fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef,
543                               box_ptr_ptr: Option<ValueRef>,
544                               t: ty::t)
545                            -> block {
546     let _icx = push_ctxt("decr_refcnt_maybe_free");
547     let ccx = bcx.ccx();
548
549     let decr_bcx = sub_block(bcx, "decr");
550     let free_bcx = sub_block(decr_bcx, "free");
551     let next_bcx = sub_block(bcx, "next");
552     CondBr(bcx, IsNotNull(bcx, box_ptr), decr_bcx.llbb, next_bcx.llbb);
553
554     let rc_ptr = GEPi(decr_bcx, box_ptr, [0u, abi::box_field_refcnt]);
555     let rc = Sub(decr_bcx, Load(decr_bcx, rc_ptr), C_int(ccx, 1));
556     Store(decr_bcx, rc, rc_ptr);
557     CondBr(decr_bcx, IsNull(decr_bcx, rc), free_bcx.llbb, next_bcx.llbb);
558
559     let free_bcx = match box_ptr_ptr {
560         Some(p) => free_ty(free_bcx, p, t),
561         None => free_ty_immediate(free_bcx, box_ptr, t)
562     };
563     Br(free_bcx, next_bcx.llbb);
564
565     next_bcx
566 }
567
568
569 pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
570     let _icx = push_ctxt("make_take_glue");
571     // NB: v is a *pointer* to type t here, not a direct value.
572     match ty::get(t).sty {
573       ty::ty_box(_) | ty::ty_opaque_box |
574       ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => {
575         incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
576       }
577       ty::ty_evec(_, ty::vstore_slice(_))
578       | ty::ty_estr(ty::vstore_slice(_)) => {
579         bcx
580       }
581       ty::ty_closure(ty::ClosureTy { sigil: ast::BorrowedSigil, _ }) |
582       ty::ty_closure(ty::ClosureTy { sigil: ast::ManagedSigil, _ }) => {
583         closure::make_closure_glue(bcx, v, t, take_ty)
584       }
585       ty::ty_closure(ty::ClosureTy { sigil: ast::OwnedSigil, _ }) => bcx,
586       ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
587         let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
588         incr_refcnt_of_boxed(bcx, llbox);
589         bcx
590       }
591       ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
592           let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]);
593           let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable]));
594
595           // Cast the vtable to a pointer to a pointer to a tydesc.
596           let llvtable = PointerCast(bcx, llvtable,
597                                      bcx.ccx().tydesc_type.ptr_to().ptr_to());
598           let lltydesc = Load(bcx, llvtable);
599           call_tydesc_glue_full(bcx,
600                                 lluniquevalue,
601                                 lltydesc,
602                                 abi::tydesc_field_take_glue,
603                                 None);
604           bcx
605       }
606       ty::ty_opaque_closure_ptr(ck) => {
607         closure::make_opaque_cbox_take_glue(bcx, ck, v)
608       }
609       ty::ty_struct(did, _) => {
610         let tcx = bcx.tcx();
611         let bcx = iter_structural_ty(bcx, v, t, take_ty);
612
613         match ty::ty_dtor(tcx, did) {
614           ty::TraitDtor(_, false) => {
615             // Zero out the struct
616             unsafe {
617                 let ty = Type::from_ref(llvm::LLVMTypeOf(v));
618                 memzero(&B(bcx), v, ty);
619             }
620
621           }
622           _ => { }
623         }
624         bcx
625       }
626       _ if ty::type_is_structural(t) => {
627         iter_structural_ty(bcx, v, t, take_ty)
628       }
629       _ => bcx
630     }
631 }
632
633 pub fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) {
634     let _icx = push_ctxt("incr_refcnt_of_boxed");
635     let ccx = cx.ccx();
636     let rc_ptr = GEPi(cx, box_ptr, [0u, abi::box_field_refcnt]);
637     let rc = Load(cx, rc_ptr);
638     let rc = Add(cx, rc, C_int(ccx, 1));
639     Store(cx, rc, rc_ptr);
640 }
641
642
643 // Generates the declaration for (but doesn't emit) a type descriptor.
644 pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info {
645     // If emit_tydescs already ran, then we shouldn't be creating any new
646     // tydescs.
647     assert!(!ccx.finished_tydescs);
648
649     let llty = type_of(ccx, t);
650
651     if ccx.sess.count_type_sizes() {
652         io::println(fmt!("%u\t%s", llsize_of_real(ccx, llty),
653                          ppaux::ty_to_str(ccx.tcx, t)));
654     }
655
656     let llsize = llsize_of(ccx, llty);
657     let llalign = llalign_of(ccx, llty);
658     let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc").to_managed();
659     note_unique_llvm_symbol(ccx, name);
660     debug!("+++ declare_tydesc %s %s", ppaux::ty_to_str(ccx.tcx, t), name);
661     let gvar = str::as_c_str(name, |buf| {
662         unsafe {
663             llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type.to_ref(), buf)
664         }
665     });
666     let inf = @mut tydesc_info {
667         ty: t,
668         tydesc: gvar,
669         size: llsize,
670         align: llalign,
671         take_glue: None,
672         drop_glue: None,
673         free_glue: None,
674         visit_glue: None
675     };
676     debug!("--- declare_tydesc %s", ppaux::ty_to_str(ccx.tcx, t));
677     return inf;
678 }
679
680 pub type glue_helper<'self> = &'self fn(block, ValueRef, ty::t) -> block;
681
682 pub fn declare_generic_glue(ccx: &mut CrateContext, t: ty::t, llfnty: Type,
683                             name: &str) -> ValueRef {
684     let _icx = push_ctxt("declare_generic_glue");
685     let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, (~"glue_" + name)).to_managed();
686     debug!("%s is for type %s", fn_nm, ppaux::ty_to_str(ccx.tcx, t));
687     note_unique_llvm_symbol(ccx, fn_nm);
688     let llfn = decl_cdecl_fn(ccx.llmod, fn_nm, llfnty);
689     set_glue_inlining(llfn, t);
690     return llfn;
691 }
692
693 pub fn make_generic_glue_inner(ccx: @mut CrateContext,
694                                t: ty::t,
695                                llfn: ValueRef,
696                                helper: glue_helper)
697                             -> ValueRef {
698     let _icx = push_ctxt("make_generic_glue_inner");
699     let fcx = new_fn_ctxt(ccx, ~[], llfn, ty::mk_nil(), None);
700     lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
701     ccx.stats.n_glues_created += 1u;
702     // All glue functions take values passed *by alias*; this is a
703     // requirement since in many contexts glue is invoked indirectly and
704     // the caller has no idea if it's dealing with something that can be
705     // passed by value.
706     //
707     // llfn is expected be declared to take a parameter of the appropriate
708     // type, so we don't need to explicitly cast the function parameter.
709
710     let bcx = fcx.entry_bcx.get();
711     let rawptr0_arg = fcx.arg_pos(0u);
712     let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, rawptr0_arg as c_uint) };
713     let bcx = helper(bcx, llrawptr0, t);
714
715     finish_fn(fcx, bcx);
716
717     return llfn;
718 }
719
720 pub fn make_generic_glue(ccx: @mut CrateContext,
721                          t: ty::t,
722                          llfn: ValueRef,
723                          helper: glue_helper,
724                          name: &str)
725                       -> ValueRef {
726     let _icx = push_ctxt("make_generic_glue");
727     let glue_name = fmt!("glue %s %s", name, ty_to_short_str(ccx.tcx, t));
728     let _s = StatRecorder::new(ccx, glue_name);
729     make_generic_glue_inner(ccx, t, llfn, helper)
730 }
731
732 pub fn emit_tydescs(ccx: &mut CrateContext) {
733     let _icx = push_ctxt("emit_tydescs");
734     // As of this point, allow no more tydescs to be created.
735     ccx.finished_tydescs = true;
736     let glue_fn_ty = Type::generic_glue_fn(ccx).ptr_to();
737     let tyds = &mut ccx.tydescs;
738     for tyds.each_value |&val| {
739         let ti = val;
740
741         // Each of the glue functions needs to be cast to a generic type
742         // before being put into the tydesc because we only have a singleton
743         // tydesc type. Then we'll recast each function to its real type when
744         // calling it.
745         let take_glue =
746             match ti.take_glue {
747               None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
748               Some(v) => {
749                 unsafe {
750                     ccx.stats.n_real_glues += 1u;
751                     llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
752                 }
753               }
754             };
755         let drop_glue =
756             match ti.drop_glue {
757               None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
758               Some(v) => {
759                 unsafe {
760                     ccx.stats.n_real_glues += 1u;
761                     llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
762                 }
763               }
764             };
765         let free_glue =
766             match ti.free_glue {
767               None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
768               Some(v) => {
769                 unsafe {
770                     ccx.stats.n_real_glues += 1u;
771                     llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
772                 }
773               }
774             };
775         let visit_glue =
776             match ti.visit_glue {
777               None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
778               Some(v) => {
779                 unsafe {
780                     ccx.stats.n_real_glues += 1u;
781                     llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
782                 }
783               }
784             };
785
786         let tydesc = C_named_struct(ccx.tydesc_type,
787                                     [ti.size, // size
788                                     ti.align, // align
789                                     take_glue, // take_glue
790                                     drop_glue, // drop_glue
791                                     free_glue, // free_glue
792                                     visit_glue]); // visit_glue
793
794         unsafe {
795             let gvar = ti.tydesc;
796             llvm::LLVMSetInitializer(gvar, tydesc);
797             llvm::LLVMSetGlobalConstant(gvar, True);
798             lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage);
799
800         }
801     };
802 }