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.
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.
13 // Code relating to taking, dropping, etc as well as type descriptors.
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;
36 use util::ppaux::ty_to_short_str;
38 use middle::trans::type_::Type;
41 use std::libc::c_uint;
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
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
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);
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);
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 {
83 | ty::ty_evec(_, ty::vstore_uniq)
84 | ty::ty_estr(ty::vstore_uniq) => {
85 free_ty_immediate(bcx, v, t)
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)
92 _ => bcx.tcx().sess.bug("drop_ty_immediate: non-box ty")
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);
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 {
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), "");
119 _ => bcx.tcx().sess.bug("free_ty_immediate: non-box ty")
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);
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) {
139 if field == abi::tydesc_field_take_glue {
140 match ty::get(t).sty {
141 ty::ty_unboxed_vec(*) => { return ty::mk_u32(); }
146 if field == abi::tydesc_field_take_glue &&
147 ty::type_is_boxed(t) {
148 return ty::mk_imm_box(tcx, ty::mk_u32());
151 if field == abi::tydesc_field_free_glue {
152 match ty::get(t).sty {
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(); }
165 if (field == abi::tydesc_field_free_glue ||
166 field == abi::tydesc_field_drop_glue) {
167 match ty::get(t).sty {
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()),
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()),
185 pub fn lazily_emit_simplified_tydesc_glue(ccx: @mut CrateContext,
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);
191 let simpl_ti = get_tydesc(ccx, simpl);
192 lazily_emit_tydesc_glue(ccx, field, simpl_ti);
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;
210 pub fn lazily_emit_tydesc_glue(ccx: @mut CrateContext,
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());
216 if lazily_emit_simplified_tydesc_glue(ccx, field, ti) {
220 if field == abi::tydesc_field_take_glue {
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));
233 } else if field == abi::tydesc_field_drop_glue {
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));
246 } else if field == abi::tydesc_field_free_glue {
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));
259 } else if field == abi::tydesc_field_visit_glue {
260 match ti.visit_glue {
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));
275 // See [Note-arg-mode]
276 pub fn call_tydesc_glue_full(bcx: block,
280 static_ti: Option<@mut tydesc_info>) {
281 let _icx = push_ctxt("call_tydesc_glue_full");
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.
286 ccx.sess.opts.debugging_opts & session::no_landing_pads != 0;
287 if bcx.unreachable && !no_lpads { return; }
289 let static_glue_fn = match static_ti {
292 lazily_emit_tydesc_glue(ccx, field, sti);
293 if field == abi::tydesc_field_take_glue {
295 } else if field == abi::tydesc_field_drop_glue {
297 } else if field == abi::tydesc_field_free_glue {
299 } else if field == abi::tydesc_field_visit_glue {
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())
313 let ty = static_ti.get().ty;
314 let simpl = simplified_glue_type(ccx.tcx, field, ty);
316 PointerCast(bcx, v, type_of(ccx, simpl).ptr_to())
323 match static_glue_fn {
325 // Select out the glue function to call from the tydesc
326 let llfnptr = GEPi(bcx, tydesc, [0u, field]);
333 Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr]);
336 // See [Note-arg-mode]
337 pub fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: uint)
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));
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| {
349 let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx()){
352 bcx.tcx().sess.fatal(s);
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);
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);
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,
384 uniq::make_free_glue(bcx, v, t)
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))
390 ty::ty_closure(_) => {
391 closure::make_closure_glue(bcx, v, t, free_ty)
393 ty::ty_opaque_closure_ptr(ck) => {
394 closure::make_opaque_cbox_free_glue(bcx, ck, v)
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| {
407 // Find and call the actual destructor
408 let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did,
409 class_did, substs.tps.clone());
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()
417 // Class dtors have no explicit args, so the params should
418 // just consist of the environment (self)
419 assert_eq!(params.len(), 1);
421 let self_arg = PointerCast(bcx, v0, params[0]);
422 let args = ~[self_arg];
424 Call(bcx, dtor_addr, args);
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);
433 Store(bcx, C_u8(0), drop_flag);
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);
442 // Find and call the actual destructor
443 let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did,
444 class_did, substs.tps.clone());
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()
452 // Class dtors have no explicit args, so the params should
453 // just consist of the environment (self)
454 assert_eq!(params.len(), 1);
456 let self_arg = PointerCast(bcx, v0, params[0]);
457 let args = ~[self_arg];
459 Call(bcx, dtor_addr, args);
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);
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");
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)
481 ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) => {
484 ty::ty_unboxed_vec(_) => {
485 tvec::make_drop_glue_unboxed(bcx, v0, t)
487 ty::ty_struct(did, ref substs) => {
489 match ty::ty_dtor(tcx, did) {
490 ty::TraitDtor(dtor, true) => {
491 trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
493 ty::TraitDtor(dtor, false) => {
494 trans_struct_drop(bcx, t, v0, dtor, did, substs)
497 // No dtor? Just the default case
498 iter_structural_ty(bcx, v0, t, drop_ty)
502 ty::ty_closure(_) => {
503 closure::make_closure_glue(bcx, v0, t, drop_ty)
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))
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]));
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,
524 abi::tydesc_field_free_glue,
529 ty::ty_opaque_closure_ptr(ck) => {
530 closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
533 if ty::type_needs_drop(ccx.tcx, t) &&
534 ty::type_is_structural(t) {
535 iter_structural_ty(bcx, v0, t, drop_ty)
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>,
546 let _icx = push_ctxt("decr_refcnt_maybe_free");
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);
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);
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)
563 Br(free_bcx, next_bcx.llbb);
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
577 ty::ty_evec(_, ty::vstore_slice(_))
578 | ty::ty_estr(ty::vstore_slice(_)) => {
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)
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);
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]));
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,
602 abi::tydesc_field_take_glue,
606 ty::ty_opaque_closure_ptr(ck) => {
607 closure::make_opaque_cbox_take_glue(bcx, ck, v)
609 ty::ty_struct(did, _) => {
611 let bcx = iter_structural_ty(bcx, v, t, take_ty);
613 match ty::ty_dtor(tcx, did) {
614 ty::TraitDtor(_, false) => {
615 // Zero out the struct
617 let ty = Type::from_ref(llvm::LLVMTypeOf(v));
618 memzero(&B(bcx), v, ty);
626 _ if ty::type_is_structural(t) => {
627 iter_structural_ty(bcx, v, t, take_ty)
633 pub fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) {
634 let _icx = push_ctxt("incr_refcnt_of_boxed");
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);
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
647 assert!(!ccx.finished_tydescs);
649 let llty = type_of(ccx, t);
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)));
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| {
663 llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type.to_ref(), buf)
666 let inf = @mut tydesc_info {
676 debug!("--- declare_tydesc %s", ppaux::ty_to_str(ccx.tcx, t));
680 pub type glue_helper<'self> = &'self fn(block, ValueRef, ty::t) -> block;
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);
693 pub fn make_generic_glue_inner(ccx: @mut CrateContext,
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
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.
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);
720 pub fn make_generic_glue(ccx: @mut CrateContext,
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)
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| {
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
747 None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
750 ccx.stats.n_real_glues += 1u;
751 llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
757 None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
760 ccx.stats.n_real_glues += 1u;
761 llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
767 None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
770 ccx.stats.n_real_glues += 1u;
771 llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
776 match ti.visit_glue {
777 None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
780 ccx.stats.n_real_glues += 1u;
781 llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
786 let tydesc = C_named_struct(ccx.tydesc_type,
789 take_glue, // take_glue
790 drop_glue, // drop_glue
791 free_glue, // free_glue
792 visit_glue]); // visit_glue
795 let gvar = ti.tydesc;
796 llvm::LLVMSetInitializer(gvar, tydesc);
797 llvm::LLVMSetGlobalConstant(gvar, True);
798 lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage);