2013-05-30 05:16:33 -05:00
|
|
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
//!
|
|
|
|
//
|
|
|
|
// Code relating to taking, dropping, etc as well as type descriptors.
|
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2013-02-25 13:11:21 -06:00
|
|
|
use back::abi;
|
|
|
|
use back::link::*;
|
2013-06-16 05:52:44 -05:00
|
|
|
use lib::llvm::{llvm, ValueRef, True};
|
2014-01-10 16:02:36 -06:00
|
|
|
use lib;
|
2013-07-15 22:42:13 -05:00
|
|
|
use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem};
|
2013-02-25 00:46:33 -06:00
|
|
|
use middle::trans::adt;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::base::*;
|
2014-01-10 16:02:36 -06:00
|
|
|
use middle::trans::build::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::callee;
|
2014-01-15 13:39:08 -06:00
|
|
|
use middle::trans::cleanup;
|
|
|
|
use middle::trans::cleanup::CleanupMethods;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::common::*;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::expr;
|
|
|
|
use middle::trans::machine::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::reflect;
|
|
|
|
use middle::trans::tvec;
|
2014-01-10 16:02:36 -06:00
|
|
|
use middle::trans::type_::Type;
|
2014-02-05 01:11:06 -06:00
|
|
|
use middle::trans::type_of::{type_of, sizing_type_of};
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::ty;
|
|
|
|
use util::ppaux::ty_to_short_str;
|
2014-01-10 16:02:36 -06:00
|
|
|
use util::ppaux;
|
2013-06-16 05:52:44 -05:00
|
|
|
|
2014-01-22 13:03:02 -06:00
|
|
|
use arena::TypedArena;
|
2013-08-03 19:13:14 -05:00
|
|
|
use std::c_str::ToCStr;
|
2013-12-21 18:41:09 -06:00
|
|
|
use std::cell::Cell;
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::libc::c_uint;
|
2013-02-25 13:11:21 -06:00
|
|
|
use syntax::ast;
|
2014-01-10 16:02:36 -06:00
|
|
|
use syntax::parse::token;
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-07 10:54:58 -06:00
|
|
|
pub fn trans_free<'a>(cx: &'a Block<'a>, v: ValueRef) -> &'a Block<'a> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_free");
|
2013-06-15 22:45:48 -05:00
|
|
|
callee::trans_lang_call(cx,
|
2013-07-15 22:42:13 -05:00
|
|
|
langcall(cx, None, "", FreeFnLangItem),
|
2013-06-15 22:45:48 -05:00
|
|
|
[PointerCast(cx, v, Type::i8p())],
|
2013-07-08 01:12:01 -05:00
|
|
|
Some(expr::Ignore)).bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-01-07 10:54:58 -06:00
|
|
|
pub fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef)
|
|
|
|
-> &'a Block<'a> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_exchange_free");
|
2013-06-15 22:45:48 -05:00
|
|
|
callee::trans_lang_call(cx,
|
2013-07-15 22:42:13 -05:00
|
|
|
langcall(cx, None, "", ExchangeFreeFnLangItem),
|
2013-06-15 22:45:48 -05:00
|
|
|
[PointerCast(cx, v, Type::i8p())],
|
2013-07-08 01:12:01 -05:00
|
|
|
Some(expr::Ignore)).bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-01-23 08:51:54 -06:00
|
|
|
pub fn take_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
2014-01-07 10:54:58 -06:00
|
|
|
-> &'a Block<'a> {
|
2012-08-28 17:54:45 -05:00
|
|
|
// NB: v is an *alias* of type t here, not a direct value.
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("take_ty");
|
2014-01-23 08:51:54 -06:00
|
|
|
match ty::get(t).sty {
|
2014-02-01 07:09:11 -06:00
|
|
|
ty::ty_box(_) => incr_refcnt_of_boxed(bcx, v),
|
2014-01-23 08:51:54 -06:00
|
|
|
_ if ty::type_is_structural(t)
|
|
|
|
&& ty::type_needs_drop(bcx.tcx(), t) => {
|
|
|
|
iter_structural_ty(bcx, v, t, take_ty)
|
|
|
|
}
|
|
|
|
_ => bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
|
|
|
|
let tcx = ccx.tcx;
|
|
|
|
if !ty::type_needs_drop(tcx, t) {
|
|
|
|
return ty::mk_i8();
|
|
|
|
}
|
|
|
|
match ty::get(t).sty {
|
|
|
|
ty::ty_box(typ) if !ty::type_needs_drop(tcx, typ) =>
|
|
|
|
ty::mk_box(tcx, ty::mk_i8()),
|
|
|
|
|
|
|
|
ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => {
|
|
|
|
let llty = sizing_type_of(ccx, typ);
|
|
|
|
// Unique boxes do not allocate for zero-size types. The standard library may assume
|
|
|
|
// that `free` is never called on the pointer returned for `~ZeroSizeType`.
|
|
|
|
if llsize_of_alloc(ccx, llty) == 0 {
|
|
|
|
ty::mk_i8()
|
|
|
|
} else {
|
|
|
|
ty::mk_uniq(tcx, ty::mk_i8())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::ty_vec(mt, ty::vstore_uniq) if !ty::type_needs_drop(tcx, mt.ty) =>
|
|
|
|
ty::mk_uniq(tcx, ty::mk_i8()),
|
|
|
|
|
|
|
|
_ => t
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
2014-01-07 10:54:58 -06:00
|
|
|
-> &'a Block<'a> {
|
2012-08-28 17:54:45 -05:00
|
|
|
// NB: v is an *alias* of type t here, not a direct value.
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("drop_ty");
|
2014-02-06 00:07:06 -06:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
if ty::type_needs_drop(bcx.tcx(), t) {
|
|
|
|
let glue = get_drop_glue(ccx, t);
|
|
|
|
let glue_type = get_drop_glue_type(ccx, t);
|
|
|
|
let ptr = if glue_type != t {
|
|
|
|
PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
|
|
|
|
} else {
|
|
|
|
v
|
|
|
|
};
|
|
|
|
Call(bcx, glue, [ptr], []);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2014-02-06 00:07:06 -06:00
|
|
|
bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-01-07 10:54:58 -06:00
|
|
|
pub fn drop_ty_immediate<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
|
|
|
-> &'a Block<'a> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("drop_ty_immediate");
|
2013-09-30 21:40:44 -05:00
|
|
|
let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
|
|
|
|
Store(bcx, v, vp);
|
|
|
|
drop_ty(bcx, vp, t)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
pub fn get_drop_glue(ccx: @CrateContext, t: ty::t) -> ValueRef {
|
|
|
|
let t = get_drop_glue_type(ccx, t);
|
|
|
|
{
|
|
|
|
let drop_glues = ccx.drop_glues.borrow();
|
|
|
|
match drop_glues.get().find(&t) {
|
|
|
|
Some(&glue) => return glue,
|
|
|
|
_ => { }
|
2012-09-12 16:48:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
let llfnty = Type::glue_fn(type_of(ccx, t).ptr_to());
|
|
|
|
let glue = declare_generic_glue(ccx, t, llfnty, "drop");
|
2012-09-12 16:48:13 -05:00
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
{
|
|
|
|
let mut drop_glues = ccx.drop_glues.borrow_mut();
|
|
|
|
drop_glues.get().insert(t, glue);
|
|
|
|
}
|
2014-01-11 08:39:32 -06:00
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
make_generic_glue(ccx, t, glue, make_drop_glue, "drop");
|
2012-09-12 16:48:13 -05:00
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
glue
|
|
|
|
}
|
2012-09-12 16:48:13 -05:00
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
pub fn lazily_emit_visit_glue(ccx: @CrateContext, ti: @tydesc_info) {
|
|
|
|
let _icx = push_ctxt("lazily_emit_visit_glue");
|
2012-09-12 16:48:13 -05:00
|
|
|
|
2014-01-11 08:39:32 -06:00
|
|
|
let llfnty = Type::glue_fn(type_of(ccx, ti.ty).ptr_to());
|
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
match ti.visit_glue.get() {
|
|
|
|
Some(_) => (),
|
|
|
|
None => {
|
|
|
|
debug!("+++ lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_str(ccx.tcx, ti.ty));
|
2013-06-27 08:04:22 -05:00
|
|
|
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "visit");
|
2013-12-21 18:41:09 -06:00
|
|
|
ti.visit_glue.set(Some(glue_fn));
|
2013-05-19 00:07:44 -05:00
|
|
|
make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit");
|
2014-02-06 00:07:06 -06:00
|
|
|
debug!("--- lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_str(ccx.tcx, ti.ty));
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// See [Note-arg-mode]
|
2014-02-06 00:07:06 -06:00
|
|
|
pub fn call_visit_glue(bcx: &Block, v: ValueRef, tydesc: ValueRef,
|
|
|
|
static_ti: Option<@tydesc_info>) {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("call_tydesc_glue_full");
|
2012-08-28 17:54:45 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
// NB: Don't short-circuit even if this block is unreachable because
|
|
|
|
// GC-based cleanup needs to the see that the roots are live.
|
2013-12-18 16:54:42 -06:00
|
|
|
if bcx.unreachable.get() && !ccx.sess.no_landing_pads() { return; }
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let static_glue_fn = match static_ti {
|
2014-01-27 06:18:36 -06:00
|
|
|
None => None,
|
|
|
|
Some(sti) => {
|
2014-02-06 00:07:06 -06:00
|
|
|
lazily_emit_visit_glue(ccx, sti);
|
|
|
|
sti.visit_glue.get()
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
// When static type info is available, avoid casting to a generic pointer.
|
2014-01-27 06:18:36 -06:00
|
|
|
let llrawptr = if static_glue_fn.is_none() {
|
Use concrete types in glue functions
We used to have concrete types in glue functions, but the way we used
to implement that broke inlining of those functions. To fix that, we
converted all glue to just take an i8* and always casted to that type.
The problem with the old implementation was that we made a wrong
assumption about the glue functions, taking it for granted that they
always take an i8*, because that's the function type expected by the
TyDesc fields. Therefore, we always ended up with some kind of cast.
But actually, we can initially have the glue with concrete types and
only cast the functions to the generic type once we actually emit the
TyDesc data.
That means that for glue calls that can be statically resolved, we don't
need any casts, unless the glue uses a simplified type. In that case we
cast the argument. And for glue calls that are resolved at runtime, we
cast the argument to i8*, because that's what the glue function in the
TyDesc expects.
Since most of out glue calls are static, this saves a lot of bitcasts.
The size of the unoptimized librustc.ll goes down by 240k lines.
2013-07-13 11:23:08 -05:00
|
|
|
PointerCast(bcx, v, Type::i8p())
|
|
|
|
} else {
|
2014-02-06 00:07:06 -06:00
|
|
|
v
|
Use concrete types in glue functions
We used to have concrete types in glue functions, but the way we used
to implement that broke inlining of those functions. To fix that, we
converted all glue to just take an i8* and always casted to that type.
The problem with the old implementation was that we made a wrong
assumption about the glue functions, taking it for granted that they
always take an i8*, because that's the function type expected by the
TyDesc fields. Therefore, we always ended up with some kind of cast.
But actually, we can initially have the glue with concrete types and
only cast the functions to the generic type once we actually emit the
TyDesc data.
That means that for glue calls that can be statically resolved, we don't
need any casts, unless the glue uses a simplified type. In that case we
cast the argument. And for glue calls that are resolved at runtime, we
cast the argument to i8*, because that's what the glue function in the
TyDesc expects.
Since most of out glue calls are static, this saves a lot of bitcasts.
The size of the unoptimized librustc.ll goes down by 240k lines.
2013-07-13 11:23:08 -05:00
|
|
|
};
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let llfn = {
|
|
|
|
match static_glue_fn {
|
2014-01-27 06:18:36 -06:00
|
|
|
None => {
|
|
|
|
// Select out the glue function to call from the tydesc
|
2014-02-06 00:07:06 -06:00
|
|
|
let llfnptr = GEPi(bcx, tydesc, [0u, abi::tydesc_field_visit_glue]);
|
2014-01-27 06:18:36 -06:00
|
|
|
Load(bcx, llfnptr)
|
|
|
|
}
|
|
|
|
Some(sgf) => sgf
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-01-27 06:18:36 -06:00
|
|
|
Call(bcx, llfn, [llrawptr], []);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-01-01 06:45:31 -06:00
|
|
|
fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
|
|
|
-> &'a Block<'a> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("make_visit_glue");
|
2014-01-15 13:39:08 -06:00
|
|
|
let mut bcx = bcx;
|
|
|
|
let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(),
|
|
|
|
ty::ReStatic) {
|
|
|
|
Ok(pair) => pair,
|
|
|
|
Err(s) => {
|
|
|
|
bcx.tcx().sess.fatal(s);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let v = PointerCast(bcx, v, type_of(bcx.ccx(), object_ty).ptr_to());
|
|
|
|
bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id);
|
|
|
|
bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-01-27 06:18:36 -06:00
|
|
|
fn trans_struct_drop_flag<'a>(bcx: &'a Block<'a>,
|
2014-01-07 10:54:58 -06:00
|
|
|
t: ty::t,
|
|
|
|
v0: ValueRef,
|
|
|
|
dtor_did: ast::DefId,
|
|
|
|
class_did: ast::DefId,
|
|
|
|
substs: &ty::substs)
|
|
|
|
-> &'a Block<'a> {
|
2013-02-25 01:20:08 -06:00
|
|
|
let repr = adt::represent_type(bcx.ccx(), t);
|
2013-02-25 03:49:21 -06:00
|
|
|
let drop_flag = adt::trans_drop_flag_ptr(bcx, repr, v0);
|
2013-11-21 17:42:55 -06:00
|
|
|
with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag)), |cx| {
|
2013-11-01 01:31:11 -05:00
|
|
|
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
|
2013-11-21 17:42:55 -06:00
|
|
|
})
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-01-27 06:18:36 -06:00
|
|
|
fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
|
2014-01-07 10:54:58 -06:00
|
|
|
t: ty::t,
|
|
|
|
v0: ValueRef,
|
|
|
|
dtor_did: ast::DefId,
|
|
|
|
class_did: ast::DefId,
|
|
|
|
substs: &ty::substs)
|
|
|
|
-> &'a Block<'a> {
|
2013-06-22 21:41:45 -05:00
|
|
|
let repr = adt::represent_type(bcx.ccx(), t);
|
|
|
|
|
|
|
|
// Find and call the actual destructor
|
|
|
|
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did,
|
2013-07-02 14:47:32 -05:00
|
|
|
class_did, substs.tps.clone());
|
2013-06-22 21:41:45 -05:00
|
|
|
|
|
|
|
// The second argument is the "self" argument for drop
|
|
|
|
let params = unsafe {
|
|
|
|
let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
|
|
|
|
ty.element_type().func_params()
|
|
|
|
};
|
|
|
|
|
|
|
|
// Class dtors have no explicit args, so the params should
|
|
|
|
// just consist of the environment (self)
|
|
|
|
assert_eq!(params.len(), 1);
|
|
|
|
|
2013-11-01 01:31:11 -05:00
|
|
|
// Be sure to put all of the fields into a scope so we can use an invoke
|
|
|
|
// instruction to call the user destructor but still call the field
|
|
|
|
// destructors if the user destructor fails.
|
2014-01-15 13:39:08 -06:00
|
|
|
let field_scope = bcx.fcx.push_custom_cleanup_scope();
|
|
|
|
|
|
|
|
let self_arg = PointerCast(bcx, v0, params[0]);
|
|
|
|
let args = ~[self_arg];
|
|
|
|
|
|
|
|
// Add all the fields as a value which needs to be cleaned at the end of
|
|
|
|
// this scope.
|
|
|
|
let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
|
|
|
|
for (i, fld) in field_tys.iter().enumerate() {
|
|
|
|
let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i);
|
|
|
|
bcx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
|
|
|
|
llfld_a,
|
|
|
|
fld.mt.ty);
|
|
|
|
}
|
2013-06-22 21:41:45 -05:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let (_, bcx) = invoke(bcx, dtor_addr, args, [], None);
|
|
|
|
|
|
|
|
bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, field_scope)
|
2013-06-22 21:41:45 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-01-27 06:18:36 -06:00
|
|
|
fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'a> {
|
2012-08-28 17:54:45 -05:00
|
|
|
// NB: v0 is an *alias* of type t here, not a direct value.
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("make_drop_glue");
|
2012-08-28 17:54:45 -05:00
|
|
|
let ccx = bcx.ccx();
|
2013-07-12 20:25:46 -05:00
|
|
|
match ty::get(t).sty {
|
2014-01-27 06:18:36 -06:00
|
|
|
ty::ty_box(body_ty) => {
|
2014-02-06 16:38:33 -06:00
|
|
|
decr_refcnt_maybe_free(bcx, v0, body_ty)
|
2014-01-27 06:18:36 -06:00
|
|
|
}
|
|
|
|
ty::ty_uniq(content_ty) => {
|
|
|
|
let llbox = Load(bcx, v0);
|
|
|
|
let not_null = IsNotNull(bcx, llbox);
|
|
|
|
with_cond(bcx, not_null, |bcx| {
|
|
|
|
let bcx = drop_ty(bcx, llbox, content_ty);
|
|
|
|
trans_exchange_free(bcx, llbox)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
ty::ty_vec(_, ty::vstore_uniq) | ty::ty_str(ty::vstore_uniq) => {
|
|
|
|
make_drop_glue(bcx, v0, tvec::expand_boxed_vec_ty(bcx.tcx(), t))
|
|
|
|
}
|
|
|
|
ty::ty_unboxed_vec(_) => {
|
|
|
|
tvec::make_drop_glue_unboxed(bcx, v0, t)
|
|
|
|
}
|
|
|
|
ty::ty_struct(did, ref substs) => {
|
|
|
|
let tcx = bcx.tcx();
|
|
|
|
match ty::ty_dtor(tcx, did) {
|
|
|
|
ty::TraitDtor(dtor, true) => {
|
|
|
|
trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
|
|
|
|
}
|
|
|
|
ty::TraitDtor(dtor, false) => {
|
|
|
|
trans_struct_drop(bcx, t, v0, dtor, did, substs)
|
|
|
|
}
|
|
|
|
ty::NoDtor => {
|
|
|
|
// No dtor? Just the default case
|
|
|
|
iter_structural_ty(bcx, v0, t, drop_ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
|
|
|
|
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
|
|
|
|
// Only drop the value when it is non-null
|
|
|
|
with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
|
2014-02-05 22:05:30 -06:00
|
|
|
let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
|
|
|
|
let dtor = Load(bcx, dtor_ptr);
|
|
|
|
Call(bcx, dtor, [PointerCast(bcx, lluniquevalue, Type::i8p())], []);
|
2014-01-27 06:18:36 -06:00
|
|
|
bcx
|
|
|
|
})
|
|
|
|
}
|
|
|
|
ty::ty_closure(ref f) if f.sigil == ast::OwnedSigil => {
|
|
|
|
let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
|
|
|
|
let env = Load(bcx, box_cell_v);
|
|
|
|
let env_ptr_ty = Type::at_box(ccx, Type::i8()).ptr_to();
|
|
|
|
let env = PointerCast(bcx, env, env_ptr_ty);
|
|
|
|
with_cond(bcx, IsNotNull(bcx, env), |bcx| {
|
2014-02-05 22:05:30 -06:00
|
|
|
let dtor_ptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]);
|
|
|
|
let dtor = Load(bcx, dtor_ptr);
|
2014-01-27 06:18:36 -06:00
|
|
|
let cdata = GEPi(bcx, env, [0u, abi::box_field_body]);
|
2014-02-05 22:05:30 -06:00
|
|
|
Call(bcx, dtor, [PointerCast(bcx, cdata, Type::i8p())], []);
|
2014-01-27 06:18:36 -06:00
|
|
|
|
2014-02-05 22:05:30 -06:00
|
|
|
// Free the environment itself
|
2014-01-27 06:18:36 -06:00
|
|
|
trans_exchange_free(bcx, env)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if ty::type_needs_drop(ccx.tcx, t) &&
|
|
|
|
ty::type_is_structural(t) {
|
|
|
|
iter_structural_ty(bcx, v0, t, drop_ty)
|
|
|
|
} else {
|
|
|
|
bcx
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-07-12 20:25:46 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-02-06 16:38:33 -06:00
|
|
|
fn decr_refcnt_maybe_free<'a>(bcx: &'a Block<'a>,
|
|
|
|
box_ptr_ptr: ValueRef,
|
|
|
|
t: ty::t) -> &'a Block<'a> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("decr_refcnt_maybe_free");
|
2014-01-15 13:39:08 -06:00
|
|
|
let fcx = bcx.fcx;
|
2012-08-28 17:54:45 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
let decr_bcx = fcx.new_temp_block("decr");
|
|
|
|
let free_bcx = fcx.new_temp_block("free");
|
|
|
|
let next_bcx = fcx.new_temp_block("next");
|
|
|
|
|
2014-01-01 06:45:31 -06:00
|
|
|
let box_ptr = Load(bcx, box_ptr_ptr);
|
2013-09-30 12:37:22 -05:00
|
|
|
let llnotnull = IsNotNull(bcx, box_ptr);
|
|
|
|
CondBr(bcx, llnotnull, decr_bcx.llbb, next_bcx.llbb);
|
2013-07-18 13:45:01 -05:00
|
|
|
|
|
|
|
let rc_ptr = GEPi(decr_bcx, box_ptr, [0u, abi::box_field_refcnt]);
|
|
|
|
let rc = Sub(decr_bcx, Load(decr_bcx, rc_ptr), C_int(ccx, 1));
|
|
|
|
Store(decr_bcx, rc, rc_ptr);
|
2014-01-01 06:45:31 -06:00
|
|
|
CondBr(decr_bcx, IsNull(decr_bcx, rc), free_bcx.llbb, next_bcx.llbb);
|
|
|
|
|
2014-01-27 06:18:36 -06:00
|
|
|
let v = Load(free_bcx, box_ptr_ptr);
|
|
|
|
let body = GEPi(free_bcx, v, [0u, abi::box_field_body]);
|
2014-02-06 16:38:33 -06:00
|
|
|
let free_bcx = drop_ty(free_bcx, body, t);
|
2014-01-27 06:18:36 -06:00
|
|
|
let free_bcx = trans_free(free_bcx, v);
|
2013-07-18 13:45:01 -05:00
|
|
|
Br(free_bcx, next_bcx.llbb);
|
|
|
|
|
|
|
|
next_bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-01-23 08:51:54 -06:00
|
|
|
fn incr_refcnt_of_boxed<'a>(bcx: &'a Block<'a>,
|
|
|
|
box_ptr_ptr: ValueRef) -> &'a Block<'a> {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("incr_refcnt_of_boxed");
|
2014-01-23 08:51:54 -06:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let box_ptr = Load(bcx, box_ptr_ptr);
|
|
|
|
let rc_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_refcnt]);
|
|
|
|
let rc = Load(bcx, rc_ptr);
|
|
|
|
let rc = Add(bcx, rc, C_int(ccx, 1));
|
|
|
|
Store(bcx, rc, rc_ptr);
|
|
|
|
bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Generates the declaration for (but doesn't emit) a type descriptor.
|
2013-12-21 18:43:43 -06:00
|
|
|
pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> @tydesc_info {
|
2012-08-28 17:54:45 -05:00
|
|
|
// If emit_tydescs already ran, then we shouldn't be creating any new
|
|
|
|
// tydescs.
|
2013-12-18 20:35:33 -06:00
|
|
|
assert!(!ccx.finished_tydescs.get());
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let llty = type_of(ccx, t);
|
|
|
|
|
|
|
|
if ccx.sess.count_type_sizes() {
|
2013-09-25 00:16:43 -05:00
|
|
|
println!("{}\t{}", llsize_of_real(ccx, llty),
|
|
|
|
ppaux::ty_to_str(ccx.tcx, t));
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
let llsize = llsize_of(ccx, llty);
|
|
|
|
let llalign = llalign_of(ccx, llty);
|
2014-01-31 14:42:39 -06:00
|
|
|
let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc");
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("+++ declare_tydesc {} {}", ppaux::ty_to_str(ccx.tcx, t), name);
|
2013-11-21 17:42:55 -06:00
|
|
|
let gvar = name.with_c_str(|buf| {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type.to_ref(), buf)
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2014-01-31 14:42:39 -06:00
|
|
|
note_unique_llvm_symbol(ccx, name);
|
2013-09-03 03:44:47 -05:00
|
|
|
|
2014-01-10 16:02:36 -06:00
|
|
|
let ty_name = token::intern_and_get_ident(ppaux::ty_to_str(ccx.tcx, t));
|
2014-01-13 17:06:50 -06:00
|
|
|
let ty_name = C_str_slice(ccx, ty_name);
|
2013-09-03 03:44:47 -05:00
|
|
|
|
2013-12-21 18:43:43 -06:00
|
|
|
let inf = @tydesc_info {
|
2013-02-04 16:02:01 -06:00
|
|
|
ty: t,
|
|
|
|
tydesc: gvar,
|
|
|
|
size: llsize,
|
|
|
|
align: llalign,
|
2013-09-03 03:44:47 -05:00
|
|
|
name: ty_name,
|
2013-12-21 18:41:09 -06:00
|
|
|
visit_glue: Cell::new(None),
|
2013-02-04 16:02:01 -06:00
|
|
|
};
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("--- declare_tydesc {}", ppaux::ty_to_str(ccx.tcx, t));
|
2012-08-28 17:54:45 -05:00
|
|
|
return inf;
|
|
|
|
}
|
|
|
|
|
2014-01-11 08:39:32 -06:00
|
|
|
fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type,
|
|
|
|
name: &str) -> ValueRef {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("declare_generic_glue");
|
2014-01-31 14:42:39 -06:00
|
|
|
let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, ~"glue_" + name);
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("{} is for type {}", fn_nm, ppaux::ty_to_str(ccx.tcx, t));
|
2014-01-14 11:17:38 -06:00
|
|
|
let llfn = decl_cdecl_fn(ccx.llmod, fn_nm, llfnty, ty::mk_nil());
|
2014-01-31 14:42:39 -06:00
|
|
|
note_unique_llvm_symbol(ccx, fn_nm);
|
2012-08-28 17:54:45 -05:00
|
|
|
return llfn;
|
|
|
|
}
|
|
|
|
|
2014-01-22 13:03:02 -06:00
|
|
|
fn make_generic_glue(ccx: @CrateContext,
|
|
|
|
t: ty::t,
|
|
|
|
llfn: ValueRef,
|
|
|
|
helper: <'a> |&'a Block<'a>, ValueRef, ty::t|
|
|
|
|
-> &'a Block<'a>,
|
|
|
|
name: &str)
|
|
|
|
-> ValueRef {
|
2014-01-11 08:39:32 -06:00
|
|
|
let _icx = push_ctxt("make_generic_glue");
|
|
|
|
let glue_name = format!("glue {} {}", name, ty_to_short_str(ccx.tcx, t));
|
|
|
|
let _s = StatRecorder::new(ccx, glue_name);
|
2014-01-07 10:54:58 -06:00
|
|
|
|
2014-01-22 13:03:02 -06:00
|
|
|
let arena = TypedArena::new();
|
2014-02-13 23:07:09 -06:00
|
|
|
let fcx = new_fn_ctxt(ccx, llfn, -1, false, ty::mk_nil(), None, None, &arena);
|
2014-01-22 13:03:02 -06:00
|
|
|
|
2014-01-15 13:39:08 -06:00
|
|
|
init_function(&fcx, false, ty::mk_nil(), None);
|
2014-01-07 10:54:58 -06:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
|
2013-12-22 14:32:37 -06:00
|
|
|
ccx.stats.n_glues_created.set(ccx.stats.n_glues_created.get() + 1u);
|
2012-08-28 17:54:45 -05:00
|
|
|
// All glue functions take values passed *by alias*; this is a
|
|
|
|
// requirement since in many contexts glue is invoked indirectly and
|
|
|
|
// the caller has no idea if it's dealing with something that can be
|
|
|
|
// passed by value.
|
Use concrete types in glue functions
We used to have concrete types in glue functions, but the way we used
to implement that broke inlining of those functions. To fix that, we
converted all glue to just take an i8* and always casted to that type.
The problem with the old implementation was that we made a wrong
assumption about the glue functions, taking it for granted that they
always take an i8*, because that's the function type expected by the
TyDesc fields. Therefore, we always ended up with some kind of cast.
But actually, we can initially have the glue with concrete types and
only cast the functions to the generic type once we actually emit the
TyDesc data.
That means that for glue calls that can be statically resolved, we don't
need any casts, unless the glue uses a simplified type. In that case we
cast the argument. And for glue calls that are resolved at runtime, we
cast the argument to i8*, because that's what the glue function in the
TyDesc expects.
Since most of out glue calls are static, this saves a lot of bitcasts.
The size of the unoptimized librustc.ll goes down by 240k lines.
2013-07-13 11:23:08 -05:00
|
|
|
//
|
|
|
|
// llfn is expected be declared to take a parameter of the appropriate
|
|
|
|
// type, so we don't need to explicitly cast the function parameter.
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-12-20 22:50:26 -06:00
|
|
|
let bcx = fcx.entry_bcx.get().unwrap();
|
2014-01-11 08:39:32 -06:00
|
|
|
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, fcx.arg_pos(0) as c_uint) };
|
2013-07-12 20:25:46 -05:00
|
|
|
let bcx = helper(bcx, llrawptr0, t);
|
2014-01-07 10:54:58 -06:00
|
|
|
finish_fn(&fcx, bcx);
|
2013-06-16 05:52:44 -05:00
|
|
|
|
2014-01-11 08:39:32 -06:00
|
|
|
llfn
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-02-06 00:07:06 -06:00
|
|
|
pub fn emit_tydescs(ccx: @CrateContext) {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("emit_tydescs");
|
2012-08-28 17:54:45 -05:00
|
|
|
// As of this point, allow no more tydescs to be created.
|
2013-12-18 20:35:33 -06:00
|
|
|
ccx.finished_tydescs.set(true);
|
2013-06-22 14:36:00 -05:00
|
|
|
let glue_fn_ty = Type::generic_glue_fn(ccx).ptr_to();
|
2013-12-18 20:15:27 -06:00
|
|
|
let mut tyds = ccx.tydescs.borrow_mut();
|
|
|
|
for (_, &val) in tyds.get().iter() {
|
2012-08-28 17:54:45 -05:00
|
|
|
let ti = val;
|
|
|
|
|
|
|
|
// Each of the glue functions needs to be cast to a generic type
|
|
|
|
// before being put into the tydesc because we only have a singleton
|
|
|
|
// tydesc type. Then we'll recast each function to its real type when
|
|
|
|
// calling it.
|
2014-02-06 00:07:06 -06:00
|
|
|
let drop_glue = unsafe {
|
|
|
|
llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref())
|
|
|
|
};
|
|
|
|
ccx.stats.n_real_glues.set(ccx.stats.n_real_glues.get() + 1);
|
2012-08-28 17:54:45 -05:00
|
|
|
let visit_glue =
|
2013-12-21 18:41:09 -06:00
|
|
|
match ti.visit_glue.get() {
|
2013-12-22 15:39:02 -06:00
|
|
|
None => {
|
|
|
|
ccx.stats.n_null_glues.set(ccx.stats.n_null_glues.get() +
|
|
|
|
1u);
|
|
|
|
C_null(glue_fn_ty)
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
Some(v) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
2013-12-22 15:41:16 -06:00
|
|
|
ccx.stats.n_real_glues.set(ccx.stats.n_real_glues.get() +
|
|
|
|
1);
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-06-16 05:52:44 -05:00
|
|
|
let tydesc = C_named_struct(ccx.tydesc_type,
|
2013-06-20 07:45:10 -05:00
|
|
|
[ti.size, // size
|
2013-08-11 12:29:14 -05:00
|
|
|
ti.align, // align
|
|
|
|
drop_glue, // drop_glue
|
|
|
|
visit_glue, // visit_glue
|
2013-09-03 03:44:47 -05:00
|
|
|
ti.name]); // name
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
|
|
|
let gvar = ti.tydesc;
|
|
|
|
llvm::LLVMSetInitializer(gvar, tydesc);
|
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
|
|
|
lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|