Skip to content

Commit

Permalink
rustc_trans: use the drop glue of T instead of Box<T> in Trait's vtab…
Browse files Browse the repository at this point in the history
…le, be it &Trait or Box<Trait>.
  • Loading branch information
eddyb committed Mar 17, 2015
1 parent c64d671 commit 3e98ab5
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 222 deletions.
4 changes: 2 additions & 2 deletions src/librustc_trans/trans/_match.rs
Expand Up @@ -660,7 +660,7 @@ fn bind_subslice_pat(bcx: Block,
offset_right: uint) -> ValueRef {
let _icx = push_ctxt("match::bind_subslice_pat");
let vec_ty = node_id_type(bcx, pat_id);
let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), ty::type_content(vec_ty)));
let unit_ty = ty::sequence_element_type(bcx.tcx(), ty::type_content(vec_ty));
let vec_datum = match_datum(val, vec_ty);
let (base, len) = vec_datum.get_vec_base_and_len(bcx);

Expand All @@ -669,7 +669,7 @@ fn bind_subslice_pat(bcx: Block,
let slice_len = Sub(bcx, len, slice_len_offset, DebugLoc::None);
let slice_ty = ty::mk_slice(bcx.tcx(),
bcx.tcx().mk_region(ty::ReStatic),
ty::mt {ty: vt.unit_ty, mutbl: ast::MutImmutable});
ty::mt {ty: unit_ty, mutbl: ast::MutImmutable});
let scratch = rvalue_scratch_datum(bcx, slice_ty, "");
Store(bcx, slice_begin,
GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_trans/trans/base.rs
Expand Up @@ -702,6 +702,10 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
let unit_ty = ty::sequence_element_type(cx.tcx(), t);
cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f);
}
ty::ty_vec(_, None) | ty::ty_str => {
let unit_ty = ty::sequence_element_type(cx.tcx(), t);
cx = tvec::iter_vec_raw(cx, data_ptr, unit_ty, info.unwrap(), f);
}
ty::ty_tup(ref args) => {
let repr = adt::represent_type(cx.ccx(), t);
for (i, arg) in args.iter().enumerate() {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_trans/trans/consts.rs
Expand Up @@ -314,7 +314,6 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
let info =
expr::unsized_info(
cx, k, e.id, ty, param_substs,
|t| ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), t),
|| const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32]));

let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span);
Expand Down
5 changes: 2 additions & 3 deletions src/librustc_trans/trans/context.rs
Expand Up @@ -102,7 +102,7 @@ pub struct LocalCrateContext<'tcx> {
monomorphized: RefCell<FnvHashMap<MonoId<'tcx>, ValueRef>>,
monomorphizing: RefCell<DefIdMap<uint>>,
/// Cache generated vtables
vtables: RefCell<FnvHashMap<(Ty<'tcx>, ty::PolyTraitRef<'tcx>), ValueRef>>,
vtables: RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, ValueRef>>,
/// Cache of constant strings,
const_cstr_cache: RefCell<FnvHashMap<InternedString, ValueRef>>,

Expand Down Expand Up @@ -614,8 +614,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local.monomorphizing
}

pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<(Ty<'tcx>, ty::PolyTraitRef<'tcx>),
ValueRef>> {
pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, ValueRef>> {
&self.local.vtables
}

Expand Down
55 changes: 16 additions & 39 deletions src/librustc_trans/trans/expr.rs
Expand Up @@ -288,64 +288,47 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
// Retrieve the information we are losing (making dynamic) in an unsizing
// adjustment.
//
// When making a dtor, we need to do different things depending on the
// ownership of the object.. mk_ty is a function for turning `unadjusted_ty`
// into a type to be destructed. If we want to end up with a Box pointer,
// then mk_ty should make a Box pointer (T -> Box<T>), if we want a
// borrowed reference then it should be T -> &T.
//
// The `unadjusted_val` argument is a bit funny. It is intended
// for use in an upcast, where the new vtable for an object will
// be drived from the old one. Hence it is a pointer to the fat
// pointer.
pub fn unsized_info_bcx<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
kind: &ty::UnsizeKind<'tcx>,
id: ast::NodeId,
unadjusted_ty: Ty<'tcx>,
unadjusted_val: ValueRef, // see above (*)
param_substs: &'tcx subst::Substs<'tcx>,
mk_ty: F)
-> ValueRef
where F: FnOnce(Ty<'tcx>) -> Ty<'tcx>
{
pub fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
kind: &ty::UnsizeKind<'tcx>,
id: ast::NodeId,
unadjusted_ty: Ty<'tcx>,
unadjusted_val: ValueRef, // see above (*)
param_substs: &'tcx subst::Substs<'tcx>)
-> ValueRef {
unsized_info(
bcx.ccx(),
kind,
id,
unadjusted_ty,
param_substs,
mk_ty,
|| Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA])))
}

// Same as `unsize_info_bcx`, but does not require a bcx -- instead it
// takes an extra closure to compute the upcast vtable.
pub fn unsized_info<'ccx, 'tcx, MK_TY, MK_UPCAST_VTABLE>(
pub fn unsized_info<'ccx, 'tcx, MK_UPCAST_VTABLE>(
ccx: &CrateContext<'ccx, 'tcx>,
kind: &ty::UnsizeKind<'tcx>,
id: ast::NodeId,
unadjusted_ty: Ty<'tcx>,
param_substs: &'tcx subst::Substs<'tcx>,
mk_ty: MK_TY,
mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above
-> ValueRef
where MK_TY: FnOnce(Ty<'tcx>) -> Ty<'tcx>,
MK_UPCAST_VTABLE: FnOnce() -> ValueRef,
where MK_UPCAST_VTABLE: FnOnce() -> ValueRef
{
// FIXME(#19596) workaround: `|t| t` causes monomorphization recursion
fn identity<T>(t: T) -> T { t }

debug!("unsized_info(kind={:?}, id={}, unadjusted_ty={})",
kind, id, unadjusted_ty.repr(ccx.tcx()));
match kind {
&ty::UnsizeLength(len) => C_uint(ccx, len),
&ty::UnsizeStruct(box ref k, tp_index) => match unadjusted_ty.sty {
ty::ty_struct(_, ref substs) => {
let ty_substs = substs.types.get_slice(subst::TypeSpace);
// The dtor for a field treats it like a value, so mk_ty
// should just be the identity function.
unsized_info(ccx, k, id, ty_substs[tp_index], param_substs,
identity, mk_upcast_vtable)
mk_upcast_vtable)
}
_ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}",
unadjusted_ty.repr(ccx.tcx())))
Expand All @@ -359,8 +342,7 @@ pub fn unsized_info<'ccx, 'tcx, MK_TY, MK_UPCAST_VTABLE>(
let trait_ref = monomorphize::apply_param_substs(ccx.tcx(),
param_substs,
&trait_ref);
let box_ty = mk_ty(unadjusted_ty);
consts::ptrcast(meth::get_vtable(ccx, box_ty, trait_ref, param_substs),
consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
Type::vtable_ptr(ccx))
}
&ty::UnsizeUpcast(_) => {
Expand Down Expand Up @@ -498,8 +480,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx()));

let info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs,
|t| ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), t));
let info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs);

// Arrange cleanup
let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
Expand Down Expand Up @@ -590,8 +571,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
bcx = datum.store_to(bcx, base);

let info = unsized_info_bcx(bcx, k, expr.id, unboxed_ty, base, bcx.fcx.param_substs,
|t| ty::mk_uniq(tcx, t));
let info = unsized_info_bcx(bcx, k, expr.id, unboxed_ty, base, bcx.fcx.param_substs);
Store(bcx, info, get_len(bcx, scratch.val));

DatumBlock::new(bcx, scratch.to_expr_datum())
Expand Down Expand Up @@ -888,10 +868,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
};

let vt =
tvec::vec_types(bcx,
ty::sequence_element_type(bcx.tcx(),
base_datum.ty));
let unit_ty = ty::sequence_element_type(bcx.tcx(), base_datum.ty);

let (base, len) = base_datum.get_vec_base_and_len(bcx);

Expand All @@ -916,8 +893,8 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
len)
});
let elt = InBoundsGEP(bcx, base, &[ix_val]);
let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
Datum::new(elt, vt.unit_ty, LvalueExpr)
let elt = PointerCast(bcx, elt, type_of::type_of(ccx, unit_ty).ptr_to());
Datum::new(elt, unit_ty, LvalueExpr)
}
};

Expand Down
97 changes: 32 additions & 65 deletions src/librustc_trans/trans/glue.rs
Expand Up @@ -32,7 +32,6 @@ use trans::datum;
use trans::debuginfo::DebugLoc;
use trans::expr;
use trans::machine::*;
use trans::tvec;
use trans::type_::Type;
use trans::type_of::{self, type_of, sizing_type_of, align_of};
use middle::ty::{self, Ty};
Expand Down Expand Up @@ -386,51 +385,34 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
let _icx = push_ctxt("make_drop_glue");
match t.sty {
ty::ty_uniq(content_ty) => {
match content_ty.sty {
ty::ty_vec(ty, None) => {
tvec::make_drop_glue_unboxed(bcx, v0, ty, true)
}
ty::ty_str => {
let unit_ty = ty::sequence_element_type(bcx.tcx(), content_ty);
tvec::make_drop_glue_unboxed(bcx, v0, unit_ty, true)
}
ty::ty_trait(..) => {
let lluniquevalue = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
// Only drop the value when it is non-null
let concrete_ptr = Load(bcx, lluniquevalue);
with_cond(bcx, IsNotNull(bcx, concrete_ptr), |bcx| {
let dtor_ptr = Load(bcx, GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]));
let dtor = Load(bcx, dtor_ptr);
Call(bcx,
dtor,
&[PointerCast(bcx, lluniquevalue, Type::i8p(bcx.ccx()))],
None,
DebugLoc::None);
bcx
})
}
ty::ty_struct(..) if !type_is_sized(bcx.tcx(), content_ty) => {
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
let llbox = Load(bcx, llval);
let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
let info = GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]);
let info = Load(bcx, info);
let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
if !type_is_sized(bcx.tcx(), content_ty) {
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
let llbox = Load(bcx, llval);
let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
let info = GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]);
let info = Load(bcx, info);
let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);

// `Box<ZeroSizeType>` does not allocate.
let needs_free = ICmp(bcx,
llvm::IntNE,
llsize,
C_uint(bcx.ccx(), 0u64),
DebugLoc::None);
with_cond(bcx, needs_free, |bcx| {
trans_exchange_free_dyn(bcx, llbox, llsize, llalign, DebugLoc::None)
})
}
_ => {
assert!(type_is_sized(bcx.tcx(), content_ty));
let llval = v0;
let llbox = Load(bcx, llval);
let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None);
trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
})
}
})
} else {
let llval = v0;
let llbox = Load(bcx, llval);
let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None);
trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
})
}
}
ty::ty_struct(did, substs) | ty::ty_enum(did, substs) => {
Expand Down Expand Up @@ -462,34 +444,19 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
}
}
}
ty::ty_closure(..) => {
iter_structural_ty(bcx,
v0,
t,
|bb, vv, tt| drop_ty(bb, vv, tt, DebugLoc::None))
}
ty::ty_trait(..) => {
// No need to do a null check here (as opposed to the Box<trait case
// above), because this happens for a trait field in an unsized
// struct. If anything is null, it is the whole struct and we won't
// get here.
let lluniquevalue = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
let dtor_ptr = Load(bcx, GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]));
let dtor = Load(bcx, dtor_ptr);
let data_ptr = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
let vtable_ptr = Load(bcx, GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]));
let dtor = Load(bcx, vtable_ptr);
Call(bcx,
dtor,
&[PointerCast(bcx, Load(bcx, lluniquevalue), Type::i8p(bcx.ccx()))],
&[PointerCast(bcx, Load(bcx, data_ptr), Type::i8p(bcx.ccx()))],
None,
DebugLoc::None);
bcx
},
ty::ty_vec(_, None) | ty::ty_str => {
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
tvec::make_drop_glue_unboxed(bcx, v0, unit_ty, false)
},
}
_ => {
assert!(type_is_sized(bcx.tcx(), t));
if bcx.fcx.type_needs_drop(t) && ty::type_is_structural(t) {
if bcx.fcx.type_needs_drop(t) {
iter_structural_ty(bcx,
v0,
t,
Expand Down
23 changes: 8 additions & 15 deletions src/librustc_trans/trans/meth.rs
Expand Up @@ -680,25 +680,19 @@ pub fn trans_object_shim<'a, 'tcx>(
///
/// The `trait_ref` encodes the erased self type. Hence if we are
/// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
/// `trait_ref` would map `T:Trait`, but `box_ty` would be
/// `Foo<T>`. This `box_ty` is primarily used to encode the destructor.
/// This will hopefully change now that DST is underway.
/// `trait_ref` would map `T:Trait`.
pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
box_ty: Ty<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
param_substs: &'tcx subst::Substs<'tcx>)
-> ValueRef
{
let tcx = ccx.tcx();
let _icx = push_ctxt("meth::get_vtable");

debug!("get_vtable(box_ty={}, trait_ref={})",
box_ty.repr(tcx),
trait_ref.repr(tcx));
debug!("get_vtable(trait_ref={})", trait_ref.repr(tcx));

// Check the cache.
let cache_key = (box_ty, trait_ref.clone());
match ccx.vtables().borrow().get(&cache_key) {
match ccx.vtables().borrow().get(&trait_ref) {
Some(&val) => { return val }
None => { }
}
Expand Down Expand Up @@ -755,15 +749,15 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,

let components: Vec<_> = vec![
// Generate a destructor for the vtable.
glue::get_drop_glue(ccx, box_ty),
glue::get_drop_glue(ccx, trait_ref.self_ty()),
C_uint(ccx, size),
C_uint(ccx, align)
].into_iter().chain(methods).collect();

let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false),
"vtable", trait_ref.def_id().node);

ccx.vtables().borrow_mut().insert(cache_key, vtable);
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
vtable
}

Expand Down Expand Up @@ -842,16 +836,15 @@ pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debug!("trans_trait_cast: trait_ref={}",
trait_ref.repr(bcx.tcx()));

let datum_ty = datum.ty;
let llbox_ty = type_of(bcx.ccx(), datum_ty);
let llty = type_of(bcx.ccx(), datum.ty);

// Store the pointer into the first half of pair.
let llboxdest = GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR]);
let llboxdest = PointerCast(bcx, llboxdest, llbox_ty.ptr_to());
let llboxdest = PointerCast(bcx, llboxdest, llty.ptr_to());
bcx = datum.store_to(bcx, llboxdest);

// Store the vtable into the second half of pair.
let vtable = get_vtable(bcx.ccx(), datum_ty, trait_ref, bcx.fcx.param_substs);
let vtable = get_vtable(bcx.ccx(), trait_ref, bcx.fcx.param_substs);
let llvtabledest = GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA]);
let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to());
Store(bcx, vtable, llvtabledest);
Expand Down

0 comments on commit 3e98ab5

Please sign in to comment.