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::*;
|
|
|
|
use driver::session;
|
|
|
|
use lib;
|
2013-06-16 05:52:44 -05:00
|
|
|
use lib::llvm::{llvm, ValueRef, True};
|
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::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::callee;
|
|
|
|
use middle::trans::closure;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::common::*;
|
|
|
|
use middle::trans::build::*;
|
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;
|
2013-06-16 05:52:44 -05:00
|
|
|
use middle::trans::type_of::type_of;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::uniq;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::ty;
|
|
|
|
use util::ppaux;
|
|
|
|
use util::ppaux::ty_to_short_str;
|
2012-12-23 16:41:37 -06:00
|
|
|
|
2013-06-16 05:52:44 -05:00
|
|
|
use middle::trans::type_::Type;
|
|
|
|
|
2013-08-03 19:13:14 -05:00
|
|
|
use std::c_str::ToCStr;
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::libc::c_uint;
|
2013-02-25 13:11:21 -06:00
|
|
|
use syntax::ast;
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn trans_free(cx: @mut Block, v: ValueRef) -> @mut Block {
|
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
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn trans_exchange_free(cx: @mut Block, v: ValueRef) -> @mut Block {
|
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
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn take_ty(cx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
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");
|
2012-08-28 17:54:45 -05:00
|
|
|
if ty::type_needs_drop(cx.tcx(), t) {
|
|
|
|
return call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
|
|
|
|
}
|
|
|
|
return cx;
|
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn drop_ty(cx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
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");
|
2012-08-28 17:54:45 -05:00
|
|
|
if ty::type_needs_drop(cx.tcx(), t) {
|
|
|
|
return call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
|
|
|
|
}
|
|
|
|
return cx;
|
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn drop_ty_immediate(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("drop_ty_immediate");
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(t).sty {
|
2013-06-15 22:45:48 -05:00
|
|
|
ty::ty_uniq(_)
|
|
|
|
| ty::ty_evec(_, ty::vstore_uniq)
|
|
|
|
| ty::ty_estr(ty::vstore_uniq) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
free_ty_immediate(bcx, v, t)
|
|
|
|
}
|
2013-06-15 22:45:48 -05:00
|
|
|
ty::ty_box(_) | ty::ty_opaque_box
|
|
|
|
| ty::ty_evec(_, ty::vstore_box)
|
|
|
|
| ty::ty_estr(ty::vstore_box) => {
|
2013-06-15 11:21:15 -05:00
|
|
|
decr_refcnt_maybe_free(bcx, v, None, t)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-05-19 00:07:44 -05:00
|
|
|
_ => bcx.tcx().sess.bug("drop_ty_immediate: non-box ty")
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn free_ty(cx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
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("free_ty");
|
2012-08-28 17:54:45 -05:00
|
|
|
if ty::type_needs_drop(cx.tcx(), t) {
|
|
|
|
return call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue);
|
|
|
|
}
|
|
|
|
return cx;
|
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn free_ty_immediate(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("free_ty_immediate");
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(t).sty {
|
2012-08-28 17:54:45 -05:00
|
|
|
ty::ty_uniq(_) |
|
|
|
|
ty::ty_evec(_, ty::vstore_uniq) |
|
|
|
|
ty::ty_estr(ty::vstore_uniq) |
|
|
|
|
ty::ty_box(_) | ty::ty_opaque_box |
|
|
|
|
ty::ty_evec(_, ty::vstore_box) |
|
|
|
|
ty::ty_estr(ty::vstore_box) |
|
|
|
|
ty::ty_opaque_closure_ptr(_) => {
|
2013-06-20 14:21:37 -05:00
|
|
|
let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
|
2012-08-28 17:54:45 -05:00
|
|
|
Store(bcx, v, vp);
|
|
|
|
free_ty(bcx, vp, t)
|
|
|
|
}
|
2013-05-19 00:07:44 -05:00
|
|
|
_ => bcx.tcx().sess.bug("free_ty_immediate: non-box ty")
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn lazily_emit_all_tydesc_glue(ccx: @mut CrateContext,
|
2013-02-04 16:02:01 -06:00
|
|
|
static_ti: @mut tydesc_info) {
|
2012-08-28 17:54:45 -05:00
|
|
|
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_take_glue, static_ti);
|
|
|
|
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti);
|
|
|
|
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_free_glue, static_ti);
|
|
|
|
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_visit_glue, static_ti);
|
|
|
|
}
|
|
|
|
|
2013-01-29 19:57:02 -06:00
|
|
|
pub fn simplified_glue_type(tcx: ty::ctxt, field: uint, t: ty::t) -> ty::t {
|
2012-09-12 16:48:13 -05:00
|
|
|
if (field == abi::tydesc_field_take_glue ||
|
|
|
|
field == abi::tydesc_field_drop_glue ||
|
|
|
|
field == abi::tydesc_field_free_glue) &&
|
|
|
|
! ty::type_needs_drop(tcx, t) {
|
2013-04-22 22:19:05 -05:00
|
|
|
return ty::mk_u32();
|
2012-09-12 16:48:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if field == abi::tydesc_field_take_glue {
|
|
|
|
match ty::get(t).sty {
|
2013-07-31 01:21:26 -05:00
|
|
|
ty::ty_unboxed_vec(*) |
|
|
|
|
ty::ty_uniq(*) |
|
|
|
|
ty::ty_estr(ty::vstore_uniq) |
|
|
|
|
ty::ty_evec(_, ty::vstore_uniq) => { return ty::mk_u32(); }
|
2012-09-12 16:48:13 -05:00
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if field == abi::tydesc_field_take_glue &&
|
|
|
|
ty::type_is_boxed(t) {
|
2013-04-22 22:19:05 -05:00
|
|
|
return ty::mk_imm_box(tcx, ty::mk_u32());
|
2012-09-12 16:48:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if field == abi::tydesc_field_free_glue {
|
|
|
|
match ty::get(t).sty {
|
2013-01-31 19:12:29 -06:00
|
|
|
ty::ty_bare_fn(*) |
|
|
|
|
ty::ty_closure(*) |
|
2012-09-12 16:48:13 -05:00
|
|
|
ty::ty_box(*) |
|
|
|
|
ty::ty_opaque_box |
|
|
|
|
ty::ty_uniq(*) |
|
|
|
|
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) |
|
|
|
|
ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) |
|
|
|
|
ty::ty_opaque_closure_ptr(*) => (),
|
2013-04-22 22:19:05 -05:00
|
|
|
_ => { return ty::mk_u32(); }
|
2012-09-12 16:48:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (field == abi::tydesc_field_free_glue ||
|
|
|
|
field == abi::tydesc_field_drop_glue) {
|
|
|
|
match ty::get(t).sty {
|
|
|
|
ty::ty_box(mt) |
|
|
|
|
ty::ty_evec(mt, ty::vstore_box)
|
|
|
|
if ! ty::type_needs_drop(tcx, mt.ty) =>
|
2013-04-22 22:19:05 -05:00
|
|
|
return ty::mk_imm_box(tcx, ty::mk_u32()),
|
2012-09-12 16:48:13 -05:00
|
|
|
|
|
|
|
ty::ty_uniq(mt) |
|
|
|
|
ty::ty_evec(mt, ty::vstore_uniq)
|
|
|
|
if ! ty::type_needs_drop(tcx, mt.ty) =>
|
2013-04-22 22:19:05 -05:00
|
|
|
return ty::mk_imm_uniq(tcx, ty::mk_u32()),
|
2012-09-12 16:48:13 -05:00
|
|
|
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn lazily_emit_simplified_tydesc_glue(ccx: @mut CrateContext,
|
2013-01-29 19:57:02 -06:00
|
|
|
field: uint,
|
2013-06-27 08:04:22 -05:00
|
|
|
ti: &mut tydesc_info) -> bool {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("lazily_emit_simplified_tydesc_glue");
|
2012-09-12 16:48:13 -05:00
|
|
|
let simpl = simplified_glue_type(ccx.tcx, field, ti.ty);
|
|
|
|
if simpl != ti.ty {
|
2013-02-25 13:11:21 -06:00
|
|
|
let simpl_ti = get_tydesc(ccx, simpl);
|
2012-09-12 16:48:13 -05:00
|
|
|
lazily_emit_tydesc_glue(ccx, field, simpl_ti);
|
2013-03-16 13:11:31 -05:00
|
|
|
{
|
|
|
|
if field == abi::tydesc_field_take_glue {
|
2013-06-15 09:46:03 -05:00
|
|
|
ti.take_glue = simpl_ti.take_glue;
|
2013-03-16 13:11:31 -05:00
|
|
|
} else if field == abi::tydesc_field_drop_glue {
|
2013-06-15 09:46:03 -05:00
|
|
|
ti.drop_glue = simpl_ti.drop_glue;
|
2013-03-16 13:11:31 -05:00
|
|
|
} else if field == abi::tydesc_field_free_glue {
|
2013-06-15 09:46:03 -05:00
|
|
|
ti.free_glue = simpl_ti.free_glue;
|
2013-03-16 13:11:31 -05:00
|
|
|
} else if field == abi::tydesc_field_visit_glue {
|
2013-06-15 09:46:03 -05:00
|
|
|
ti.visit_glue = simpl_ti.visit_glue;
|
2013-03-16 13:11:31 -05:00
|
|
|
}
|
2012-09-12 16:48:13 -05:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn lazily_emit_tydesc_glue(ccx: @mut CrateContext,
|
2013-01-29 19:57:02 -06:00
|
|
|
field: uint,
|
2013-02-04 16:02:01 -06:00
|
|
|
ti: @mut tydesc_info) {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("lazily_emit_tydesc_glue");
|
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
|
|
|
let llfnty = Type::glue_fn(type_of::type_of(ccx, ti.ty).ptr_to());
|
2012-09-12 16:48:13 -05:00
|
|
|
|
|
|
|
if lazily_emit_simplified_tydesc_glue(ccx, field, ti) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
if field == abi::tydesc_field_take_glue {
|
|
|
|
match ti.take_glue {
|
|
|
|
Some(_) => (),
|
|
|
|
None => {
|
|
|
|
debug!("+++ lazily_emit_tydesc_glue TAKE %s",
|
|
|
|
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, "take");
|
2012-08-28 17:54:45 -05:00
|
|
|
ti.take_glue = Some(glue_fn);
|
2013-05-19 00:07:44 -05:00
|
|
|
make_generic_glue(ccx, ti.ty, glue_fn, make_take_glue, "take");
|
2012-08-28 17:54:45 -05:00
|
|
|
debug!("--- lazily_emit_tydesc_glue TAKE %s",
|
|
|
|
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if field == abi::tydesc_field_drop_glue {
|
|
|
|
match ti.drop_glue {
|
|
|
|
Some(_) => (),
|
|
|
|
None => {
|
|
|
|
debug!("+++ lazily_emit_tydesc_glue DROP %s",
|
|
|
|
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, "drop");
|
2012-08-28 17:54:45 -05:00
|
|
|
ti.drop_glue = Some(glue_fn);
|
2013-05-19 00:07:44 -05:00
|
|
|
make_generic_glue(ccx, ti.ty, glue_fn, make_drop_glue, "drop");
|
2012-08-28 17:54:45 -05:00
|
|
|
debug!("--- lazily_emit_tydesc_glue DROP %s",
|
|
|
|
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if field == abi::tydesc_field_free_glue {
|
|
|
|
match ti.free_glue {
|
|
|
|
Some(_) => (),
|
|
|
|
None => {
|
|
|
|
debug!("+++ lazily_emit_tydesc_glue FREE %s",
|
|
|
|
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, "free");
|
2012-08-28 17:54:45 -05:00
|
|
|
ti.free_glue = Some(glue_fn);
|
2013-05-19 00:07:44 -05:00
|
|
|
make_generic_glue(ccx, ti.ty, glue_fn, make_free_glue, "free");
|
2012-08-28 17:54:45 -05:00
|
|
|
debug!("--- lazily_emit_tydesc_glue FREE %s",
|
|
|
|
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if field == abi::tydesc_field_visit_glue {
|
|
|
|
match ti.visit_glue {
|
|
|
|
Some(_) => (),
|
|
|
|
None => {
|
|
|
|
debug!("+++ lazily_emit_tydesc_glue VISIT %s",
|
|
|
|
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");
|
2012-08-28 17:54:45 -05:00
|
|
|
ti.visit_glue = Some(glue_fn);
|
2013-05-19 00:07:44 -05:00
|
|
|
make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit");
|
2012-08-28 17:54:45 -05:00
|
|
|
debug!("--- lazily_emit_tydesc_glue VISIT %s",
|
|
|
|
ppaux::ty_to_str(ccx.tcx, ti.ty));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// See [Note-arg-mode]
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn call_tydesc_glue_full(bcx: @mut Block,
|
2013-02-04 16:02:01 -06:00
|
|
|
v: ValueRef,
|
|
|
|
tydesc: ValueRef,
|
|
|
|
field: uint,
|
|
|
|
static_ti: Option<@mut 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.
|
|
|
|
let no_lpads =
|
|
|
|
ccx.sess.opts.debugging_opts & session::no_landing_pads != 0;
|
|
|
|
if bcx.unreachable && !no_lpads { return; }
|
|
|
|
|
|
|
|
let static_glue_fn = match static_ti {
|
|
|
|
None => None,
|
|
|
|
Some(sti) => {
|
|
|
|
lazily_emit_tydesc_glue(ccx, field, sti);
|
|
|
|
if field == abi::tydesc_field_take_glue {
|
|
|
|
sti.take_glue
|
|
|
|
} else if field == abi::tydesc_field_drop_glue {
|
|
|
|
sti.drop_glue
|
|
|
|
} else if field == abi::tydesc_field_free_glue {
|
|
|
|
sti.free_glue
|
|
|
|
} else if field == abi::tydesc_field_visit_glue {
|
|
|
|
sti.visit_glue
|
|
|
|
} else {
|
|
|
|
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
|
|
|
// When static type info is available, avoid casting parameter unless the
|
|
|
|
// glue is using a simplified type, because the function already has the
|
|
|
|
// right type. Otherwise cast to generic pointer.
|
|
|
|
let llrawptr = if static_ti.is_none() || static_glue_fn.is_none() {
|
|
|
|
PointerCast(bcx, v, Type::i8p())
|
|
|
|
} else {
|
2013-08-03 18:59:24 -05:00
|
|
|
let ty = static_ti.unwrap().ty;
|
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
|
|
|
let simpl = simplified_glue_type(ccx.tcx, field, ty);
|
|
|
|
if simpl != ty {
|
|
|
|
PointerCast(bcx, v, type_of(ccx, simpl).ptr_to())
|
|
|
|
} else {
|
|
|
|
v
|
|
|
|
}
|
|
|
|
};
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let llfn = {
|
|
|
|
match static_glue_fn {
|
|
|
|
None => {
|
|
|
|
// Select out the glue function to call from the tydesc
|
|
|
|
let llfnptr = GEPi(bcx, tydesc, [0u, field]);
|
|
|
|
Load(bcx, llfnptr)
|
|
|
|
}
|
|
|
|
Some(sgf) => sgf
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-09-12 23:14:17 -05:00
|
|
|
Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr], []);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// See [Note-arg-mode]
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn call_tydesc_glue(cx: @mut Block, v: ValueRef, t: ty::t, field: uint)
|
|
|
|
-> @mut Block {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("call_tydesc_glue");
|
2012-08-28 17:54:45 -05:00
|
|
|
let ti = get_tydesc(cx.ccx(), t);
|
|
|
|
call_tydesc_glue_full(cx, v, ti.tydesc, field, Some(ti));
|
|
|
|
return cx;
|
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn make_visit_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("make_visit_glue");
|
2013-07-12 20:25:46 -05:00
|
|
|
do with_scope(bcx, None, "visitor cleanup") |bcx| {
|
2013-05-02 20:42:07 -05:00
|
|
|
let mut bcx = bcx;
|
2013-08-11 12:58:01 -05:00
|
|
|
let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(),
|
|
|
|
ty::re_static) {
|
2013-07-15 22:42:13 -05:00
|
|
|
Ok(pair) => pair,
|
|
|
|
Err(s) => {
|
|
|
|
bcx.tcx().sess.fatal(s);
|
|
|
|
}
|
|
|
|
};
|
2013-06-15 22:45:48 -05:00
|
|
|
let v = PointerCast(bcx, v, type_of::type_of(bcx.ccx(), object_ty).ptr_to());
|
2013-05-02 20:42:07 -05:00
|
|
|
bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id);
|
|
|
|
// The visitor is a boxed object and needs to be dropped
|
|
|
|
add_clean(bcx, v, object_ty);
|
|
|
|
bcx
|
2013-07-12 20:25:46 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn make_free_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
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_free_glue");
|
2013-07-12 20:25:46 -05:00
|
|
|
match ty::get(t).sty {
|
2012-08-28 17:54:45 -05:00
|
|
|
ty::ty_box(body_mt) => {
|
|
|
|
let v = Load(bcx, v);
|
|
|
|
let body = GEPi(bcx, v, [0u, abi::box_field_body]);
|
|
|
|
let bcx = drop_ty(bcx, body, body_mt.ty);
|
|
|
|
trans_free(bcx, v)
|
|
|
|
}
|
|
|
|
ty::ty_opaque_box => {
|
|
|
|
let v = Load(bcx, v);
|
|
|
|
let td = Load(bcx, GEPi(bcx, v, [0u, abi::box_field_tydesc]));
|
|
|
|
let valptr = GEPi(bcx, v, [0u, abi::box_field_body]);
|
|
|
|
// Generate code that, dynamically, indexes into the
|
|
|
|
// tydesc and calls the drop glue that got set dynamically
|
|
|
|
call_tydesc_glue_full(bcx, valptr, td, abi::tydesc_field_drop_glue,
|
|
|
|
None);
|
|
|
|
trans_free(bcx, v)
|
|
|
|
}
|
|
|
|
ty::ty_uniq(*) => {
|
|
|
|
uniq::make_free_glue(bcx, v, t)
|
|
|
|
}
|
2013-07-15 13:23:42 -05:00
|
|
|
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) |
|
2012-08-28 17:54:45 -05:00
|
|
|
ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => {
|
2013-07-12 20:25:46 -05:00
|
|
|
make_free_glue(bcx, v, tvec::expand_boxed_vec_ty(bcx.tcx(), t))
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-01-31 19:12:29 -06:00
|
|
|
ty::ty_closure(_) => {
|
|
|
|
closure::make_closure_glue(bcx, v, t, free_ty)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
ty::ty_opaque_closure_ptr(ck) => {
|
|
|
|
closure::make_opaque_cbox_free_glue(bcx, ck, v)
|
|
|
|
}
|
|
|
|
_ => bcx
|
2013-07-12 20:25:46 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
pub fn trans_struct_drop_flag(bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did: ast::DefId,
|
|
|
|
class_did: ast::DefId, substs: &ty::substs) -> @mut Block {
|
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);
|
2012-08-28 17:54:45 -05:00
|
|
|
do with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) |cx| {
|
|
|
|
let mut bcx = cx;
|
|
|
|
|
|
|
|
// 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());
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// The second argument is the "self" argument for drop
|
2013-01-10 23:23:07 -06:00
|
|
|
let params = unsafe {
|
2013-06-16 05:52:44 -05:00
|
|
|
let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
|
|
|
|
ty.element_type().func_params()
|
2013-01-10 23:23:07 -06:00
|
|
|
};
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// Class dtors have no explicit args, so the params should
|
2013-05-22 01:17:04 -05:00
|
|
|
// just consist of the environment (self)
|
|
|
|
assert_eq!(params.len(), 1);
|
2012-11-28 17:42:16 -06:00
|
|
|
|
2013-06-27 18:40:27 -05:00
|
|
|
let self_arg = PointerCast(bcx, v0, params[0]);
|
2013-05-22 01:17:04 -05:00
|
|
|
let args = ~[self_arg];
|
2013-04-18 17:53:29 -05:00
|
|
|
|
2013-09-12 23:14:17 -05:00
|
|
|
Call(bcx, dtor_addr, args, []);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// Drop the fields
|
2013-05-03 20:51:58 -05:00
|
|
|
let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
|
2013-08-03 11:45:23 -05:00
|
|
|
for (i, fld) in field_tys.iter().enumerate() {
|
2013-03-02 18:08:49 -06:00
|
|
|
let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i);
|
2012-08-28 17:54:45 -05:00
|
|
|
bcx = drop_ty(bcx, llfld_a, fld.mt.ty);
|
|
|
|
}
|
|
|
|
|
2012-09-26 21:40:05 -05:00
|
|
|
Store(bcx, C_u8(0), drop_flag);
|
2012-08-28 17:54:45 -05:00
|
|
|
bcx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
pub fn trans_struct_drop(mut bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did: ast::DefId,
|
|
|
|
class_did: ast::DefId, substs: &ty::substs) -> @mut Block {
|
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-06-27 18:40:27 -05:00
|
|
|
let self_arg = PointerCast(bcx, v0, params[0]);
|
2013-06-22 21:41:45 -05:00
|
|
|
let args = ~[self_arg];
|
|
|
|
|
2013-09-12 23:14:17 -05:00
|
|
|
Call(bcx, dtor_addr, args, []);
|
2013-06-22 21:41:45 -05:00
|
|
|
|
|
|
|
// Drop the fields
|
|
|
|
let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
|
2013-08-03 11:45:23 -05:00
|
|
|
for (i, fld) in field_tys.iter().enumerate() {
|
2013-06-22 21:41:45 -05:00
|
|
|
let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i);
|
|
|
|
bcx = drop_ty(bcx, llfld_a, fld.mt.ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
bcx
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn make_drop_glue(bcx: @mut Block, v0: ValueRef, t: ty::t) -> @mut Block {
|
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 {
|
2012-08-28 17:54:45 -05:00
|
|
|
ty::ty_box(_) | ty::ty_opaque_box |
|
|
|
|
ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) => {
|
2013-06-15 11:21:15 -05:00
|
|
|
decr_refcnt_maybe_free(bcx, Load(bcx, v0), Some(v0), t)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
ty::ty_uniq(_) |
|
|
|
|
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) => {
|
|
|
|
free_ty(bcx, v0, t)
|
|
|
|
}
|
|
|
|
ty::ty_unboxed_vec(_) => {
|
|
|
|
tvec::make_drop_glue_unboxed(bcx, v0, t)
|
|
|
|
}
|
2012-12-10 15:47:54 -06:00
|
|
|
ty::ty_struct(did, ref substs) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
let tcx = bcx.tcx();
|
|
|
|
match ty::ty_dtor(tcx, did) {
|
2013-06-22 21:41:45 -05:00
|
|
|
ty::TraitDtor(dtor, true) => {
|
|
|
|
trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
|
|
|
|
}
|
|
|
|
ty::TraitDtor(dtor, false) => {
|
2013-05-01 22:30:05 -05:00
|
|
|
trans_struct_drop(bcx, t, v0, dtor, did, substs)
|
2012-11-28 17:42:16 -06:00
|
|
|
}
|
|
|
|
ty::NoDtor => {
|
2012-08-28 17:54:45 -05:00
|
|
|
// No dtor? Just the default case
|
|
|
|
iter_structural_ty(bcx, v0, t, drop_ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-01-31 19:12:29 -06:00
|
|
|
ty::ty_closure(_) => {
|
|
|
|
closure::make_closure_glue(bcx, v0, t, drop_ty)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-06-17 14:16:30 -05:00
|
|
|
ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
|
2013-06-15 11:21:15 -05:00
|
|
|
let llbox_ptr = GEPi(bcx, v0, [0u, abi::trt_field_box]);
|
|
|
|
let llbox = Load(bcx, llbox_ptr);
|
|
|
|
decr_refcnt_maybe_free(bcx, llbox, Some(llbox_ptr),
|
|
|
|
ty::mk_opaque_box(ccx.tcx))
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-06-17 14:16:30 -05:00
|
|
|
ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
|
2013-05-23 17:22:04 -05:00
|
|
|
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
|
|
|
|
// Only drop the value when it is non-null
|
|
|
|
do with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue))) |bcx| {
|
|
|
|
let llvtable = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
|
|
|
|
|
|
|
|
// Cast the vtable to a pointer to a pointer to a tydesc.
|
2013-06-15 22:45:48 -05:00
|
|
|
let llvtable = PointerCast(bcx, llvtable,
|
|
|
|
ccx.tydesc_type.ptr_to().ptr_to());
|
2013-05-23 17:22:04 -05:00
|
|
|
let lltydesc = Load(bcx, llvtable);
|
|
|
|
call_tydesc_glue_full(bcx,
|
|
|
|
lluniquevalue,
|
|
|
|
lltydesc,
|
|
|
|
abi::tydesc_field_free_glue,
|
|
|
|
None);
|
|
|
|
bcx
|
|
|
|
}
|
2012-10-05 18:55:42 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
ty::ty_opaque_closure_ptr(ck) => {
|
|
|
|
closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if ty::type_needs_drop(ccx.tcx, t) &&
|
|
|
|
ty::type_is_structural(t) {
|
|
|
|
iter_structural_ty(bcx, v0, t, drop_ty)
|
|
|
|
} else { bcx }
|
|
|
|
}
|
2013-07-12 20:25:46 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-06-15 11:21:15 -05:00
|
|
|
// box_ptr_ptr is optional, it is constructed if not supplied.
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn decr_refcnt_maybe_free(bcx: @mut Block, box_ptr: ValueRef,
|
2013-06-15 11:21:15 -05:00
|
|
|
box_ptr_ptr: Option<ValueRef>,
|
|
|
|
t: ty::t)
|
2013-07-17 05:12:08 -05:00
|
|
|
-> @mut Block {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("decr_refcnt_maybe_free");
|
2012-08-28 17:54:45 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
2013-07-18 13:45:01 -05:00
|
|
|
let decr_bcx = sub_block(bcx, "decr");
|
|
|
|
let free_bcx = sub_block(decr_bcx, "free");
|
|
|
|
let next_bcx = sub_block(bcx, "next");
|
|
|
|
CondBr(bcx, IsNotNull(bcx, box_ptr), decr_bcx.llbb, next_bcx.llbb);
|
|
|
|
|
|
|
|
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);
|
|
|
|
CondBr(decr_bcx, IsNull(decr_bcx, rc), free_bcx.llbb, next_bcx.llbb);
|
|
|
|
|
|
|
|
let free_bcx = match box_ptr_ptr {
|
|
|
|
Some(p) => free_ty(free_bcx, p, t),
|
|
|
|
None => free_ty_immediate(free_bcx, box_ptr, t)
|
|
|
|
};
|
|
|
|
Br(free_bcx, next_bcx.llbb);
|
|
|
|
|
|
|
|
next_bcx
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn make_take_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("make_take_glue");
|
2012-08-28 17:54:45 -05:00
|
|
|
// NB: v is a *pointer* to type t here, not a direct value.
|
2013-07-12 20:25:46 -05:00
|
|
|
match ty::get(t).sty {
|
2012-08-28 17:54:45 -05:00
|
|
|
ty::ty_box(_) | ty::ty_opaque_box |
|
|
|
|
ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => {
|
|
|
|
incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
|
|
|
|
}
|
|
|
|
ty::ty_evec(_, ty::vstore_slice(_))
|
|
|
|
| ty::ty_estr(ty::vstore_slice(_)) => {
|
|
|
|
bcx
|
|
|
|
}
|
2013-09-10 20:57:24 -05:00
|
|
|
ty::ty_closure(_) => bcx,
|
2013-06-17 14:16:30 -05:00
|
|
|
ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
|
2013-05-01 03:59:36 -05:00
|
|
|
let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
|
2012-08-28 17:54:45 -05:00
|
|
|
incr_refcnt_of_boxed(bcx, llbox);
|
|
|
|
bcx
|
|
|
|
}
|
2013-06-17 14:16:30 -05:00
|
|
|
ty::ty_trait(_, _, ty::UniqTraitStore, _, _) => {
|
2013-06-22 02:37:40 -05:00
|
|
|
let lluniquevalue = GEPi(bcx, v, [0, abi::trt_field_box]);
|
|
|
|
let llvtable = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_vtable]));
|
|
|
|
|
|
|
|
// Cast the vtable to a pointer to a pointer to a tydesc.
|
|
|
|
let llvtable = PointerCast(bcx, llvtable,
|
|
|
|
bcx.ccx().tydesc_type.ptr_to().ptr_to());
|
|
|
|
let lltydesc = Load(bcx, llvtable);
|
|
|
|
call_tydesc_glue_full(bcx,
|
|
|
|
lluniquevalue,
|
|
|
|
lltydesc,
|
|
|
|
abi::tydesc_field_take_glue,
|
|
|
|
None);
|
|
|
|
bcx
|
2012-10-31 17:09:26 -05:00
|
|
|
}
|
2013-09-10 20:57:24 -05:00
|
|
|
ty::ty_opaque_closure_ptr(_) => bcx,
|
2013-06-27 08:04:22 -05:00
|
|
|
ty::ty_struct(did, _) => {
|
2013-06-24 23:39:56 -05:00
|
|
|
let tcx = bcx.tcx();
|
|
|
|
let bcx = iter_structural_ty(bcx, v, t, take_ty);
|
|
|
|
|
|
|
|
match ty::ty_dtor(tcx, did) {
|
2013-06-27 08:04:22 -05:00
|
|
|
ty::TraitDtor(_, false) => {
|
2013-06-24 23:39:56 -05:00
|
|
|
// Zero out the struct
|
|
|
|
unsafe {
|
|
|
|
let ty = Type::from_ref(llvm::LLVMTypeOf(v));
|
2013-07-21 09:19:34 -05:00
|
|
|
memzero(&B(bcx), v, ty);
|
2013-06-24 23:39:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
_ => { }
|
|
|
|
}
|
|
|
|
bcx
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
_ if ty::type_is_structural(t) => {
|
|
|
|
iter_structural_ty(bcx, v, t, take_ty)
|
|
|
|
}
|
|
|
|
_ => bcx
|
2013-07-12 20:25:46 -05:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub fn incr_refcnt_of_boxed(cx: @mut Block, box_ptr: ValueRef) {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("incr_refcnt_of_boxed");
|
2012-08-28 17:54:45 -05:00
|
|
|
let ccx = cx.ccx();
|
|
|
|
let rc_ptr = GEPi(cx, box_ptr, [0u, abi::box_field_refcnt]);
|
|
|
|
let rc = Load(cx, rc_ptr);
|
|
|
|
let rc = Add(cx, rc, C_int(ccx, 1));
|
|
|
|
Store(cx, rc, rc_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Generates the declaration for (but doesn't emit) a type descriptor.
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut 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-06-13 02:19:50 -05:00
|
|
|
assert!(!ccx.finished_tydescs);
|
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
|
|
|
}
|
|
|
|
|
2013-08-11 12:29:14 -05:00
|
|
|
let has_header = match ty::get(t).sty {
|
|
|
|
ty::ty_box(*) => true,
|
|
|
|
ty::ty_uniq(*) => ty::type_contents(ccx.tcx, t).contains_managed(),
|
|
|
|
_ => false
|
|
|
|
};
|
|
|
|
|
|
|
|
let borrow_offset = if has_header {
|
|
|
|
ccx.offsetof_gep(llty, [0u, abi::box_field_body])
|
|
|
|
} else {
|
|
|
|
C_uint(ccx, 0)
|
|
|
|
};
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
let llsize = llsize_of(ccx, llty);
|
|
|
|
let llalign = llalign_of(ccx, llty);
|
2013-06-12 12:02:55 -05:00
|
|
|
let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc").to_managed();
|
2013-04-15 21:06:36 -05:00
|
|
|
note_unique_llvm_symbol(ccx, name);
|
2013-06-12 12:02:55 -05:00
|
|
|
debug!("+++ declare_tydesc %s %s", ppaux::ty_to_str(ccx.tcx, t), name);
|
2013-08-14 21:21:59 -05:00
|
|
|
let gvar = do 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-07-22 23:41:46 -05:00
|
|
|
};
|
2013-09-03 03:44:47 -05:00
|
|
|
|
|
|
|
let ty_name = C_estr_slice(ccx, ppaux::ty_to_str(ccx.tcx, t).to_managed());
|
|
|
|
|
2013-02-04 16:02:01 -06:00
|
|
|
let inf = @mut tydesc_info {
|
|
|
|
ty: t,
|
|
|
|
tydesc: gvar,
|
|
|
|
size: llsize,
|
|
|
|
align: llalign,
|
2013-08-11 12:29:14 -05:00
|
|
|
borrow_offset: borrow_offset,
|
2013-09-03 03:44:47 -05:00
|
|
|
name: ty_name,
|
2013-02-04 16:02:01 -06:00
|
|
|
take_glue: None,
|
|
|
|
drop_glue: None,
|
|
|
|
free_glue: None,
|
|
|
|
visit_glue: None
|
|
|
|
};
|
2013-03-08 14:39:42 -06:00
|
|
|
debug!("--- declare_tydesc %s", ppaux::ty_to_str(ccx.tcx, t));
|
2012-08-28 17:54:45 -05:00
|
|
|
return inf;
|
|
|
|
}
|
|
|
|
|
2013-07-17 05:12:08 -05:00
|
|
|
pub type glue_helper<'self> = &'self fn(@mut Block, ValueRef, ty::t) -> @mut Block;
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn declare_generic_glue(ccx: &mut CrateContext, t: ty::t, llfnty: Type,
|
|
|
|
name: &str) -> ValueRef {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("declare_generic_glue");
|
2013-06-12 12:02:55 -05:00
|
|
|
let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, (~"glue_" + name)).to_managed();
|
|
|
|
debug!("%s is for type %s", fn_nm, ppaux::ty_to_str(ccx.tcx, t));
|
2013-04-15 21:06:36 -05:00
|
|
|
note_unique_llvm_symbol(ccx, fn_nm);
|
2013-06-12 12:02:55 -05:00
|
|
|
let llfn = decl_cdecl_fn(ccx.llmod, fn_nm, llfnty);
|
2012-08-28 17:54:45 -05:00
|
|
|
set_glue_inlining(llfn, t);
|
|
|
|
return llfn;
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn make_generic_glue_inner(ccx: @mut CrateContext,
|
2013-01-29 19:57:02 -06:00
|
|
|
t: ty::t,
|
|
|
|
llfn: ValueRef,
|
|
|
|
helper: glue_helper)
|
|
|
|
-> ValueRef {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("make_generic_glue_inner");
|
2013-05-27 20:33:57 -05:00
|
|
|
let fcx = new_fn_ctxt(ccx, ~[], llfn, ty::mk_nil(), None);
|
2012-08-28 17:54:45 -05:00
|
|
|
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
|
|
|
|
ccx.stats.n_glues_created += 1u;
|
|
|
|
// 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-08-03 18:59:24 -05:00
|
|
|
let bcx = fcx.entry_bcx.unwrap();
|
2013-06-22 14:36:00 -05:00
|
|
|
let rawptr0_arg = fcx.arg_pos(0u);
|
2013-05-27 20:33:57 -05:00
|
|
|
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, rawptr0_arg as c_uint) };
|
2013-07-12 20:25:46 -05:00
|
|
|
let bcx = helper(bcx, llrawptr0, t);
|
2013-06-16 05:52:44 -05:00
|
|
|
|
2013-07-21 09:19:34 -05:00
|
|
|
finish_fn(fcx, bcx);
|
2013-06-16 05:52:44 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
return llfn;
|
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn make_generic_glue(ccx: @mut CrateContext,
|
2013-04-18 17:53:29 -05:00
|
|
|
t: ty::t,
|
|
|
|
llfn: ValueRef,
|
|
|
|
helper: glue_helper,
|
|
|
|
name: &str)
|
2013-01-29 19:57:02 -06:00
|
|
|
-> ValueRef {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("make_generic_glue");
|
2013-06-28 13:15:34 -05:00
|
|
|
let glue_name = fmt!("glue %s %s", name, ty_to_short_str(ccx.tcx, t));
|
|
|
|
let _s = StatRecorder::new(ccx, glue_name);
|
|
|
|
make_generic_glue_inner(ccx, t, llfn, helper)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn emit_tydescs(ccx: &mut 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-06-13 02:19:50 -05:00
|
|
|
ccx.finished_tydescs = true;
|
2013-06-22 14:36:00 -05:00
|
|
|
let glue_fn_ty = Type::generic_glue_fn(ccx).ptr_to();
|
2013-06-13 02:19:50 -05:00
|
|
|
let tyds = &mut ccx.tydescs;
|
2013-08-03 11:45:23 -05:00
|
|
|
for (_, &val) in tyds.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.
|
|
|
|
let take_glue =
|
2013-03-20 00:17:42 -05:00
|
|
|
match ti.take_glue {
|
2012-08-28 17:54:45 -05:00
|
|
|
None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
|
|
|
Some(v) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
|
|
|
ccx.stats.n_real_glues += 1u;
|
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
|
|
|
}
|
|
|
|
};
|
|
|
|
let drop_glue =
|
2013-03-20 00:17:42 -05:00
|
|
|
match ti.drop_glue {
|
2012-08-28 17:54:45 -05:00
|
|
|
None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
|
|
|
Some(v) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
|
|
|
ccx.stats.n_real_glues += 1u;
|
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
|
|
|
}
|
|
|
|
};
|
|
|
|
let free_glue =
|
2013-03-20 00:17:42 -05:00
|
|
|
match ti.free_glue {
|
2012-08-28 17:54:45 -05:00
|
|
|
None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
|
|
|
Some(v) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
|
|
|
ccx.stats.n_real_glues += 1u;
|
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
|
|
|
}
|
|
|
|
};
|
|
|
|
let visit_glue =
|
2013-03-20 00:17:42 -05:00
|
|
|
match ti.visit_glue {
|
2012-08-28 17:54:45 -05:00
|
|
|
None => { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
|
|
|
Some(v) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
|
|
|
ccx.stats.n_real_glues += 1u;
|
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-08-11 12:29:14 -05:00
|
|
|
debug!("ti.borrow_offset: %s",
|
|
|
|
ccx.tn.val_to_str(ti.borrow_offset));
|
|
|
|
|
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
|
|
|
|
take_glue, // take_glue
|
|
|
|
drop_glue, // drop_glue
|
|
|
|
free_glue, // free_glue
|
|
|
|
visit_glue, // visit_glue
|
2013-09-03 03:44:47 -05:00
|
|
|
ti.borrow_offset, // borrow_offset
|
|
|
|
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
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|