diff options
| author | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2017-03-08 21:21:27 +0200 |
|---|---|---|
| committer | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2017-03-18 02:53:07 +0200 |
| commit | a5e3c3d5b85e415ad2094f476d9f1ac29a48e413 (patch) | |
| tree | e6a706d8aee71cacd92f4417e114bf22806c8576 | |
| parent | 65a4266f1f4ce9dac5a6ef588443b7cac911d265 (diff) | |
| download | rust-a5e3c3d5b85e415ad2094f476d9f1ac29a48e413.tar.gz rust-a5e3c3d5b85e415ad2094f476d9f1ac29a48e413.zip | |
collector: collect functions when they are called/reified
This avoids the creation of unneeded vtable shims.
| -rw-r--r-- | src/librustc_trans/collector.rs | 179 |
1 files changed, 86 insertions, 93 deletions
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 2113b9b203c..40a89783d91 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -202,7 +202,6 @@ use rustc::mir::{self, Location}; use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; -use syntax::abi::Abi; use context::SharedCrateContext; use common::{def_ty, instance_ty}; use glue::{self, DropGlueKind}; @@ -486,6 +485,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output); } } + mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => { + let fn_ty = operand.ty(self.mir, self.scx.tcx()); + let fn_ty = monomorphize::apply_param_substs( + self.scx, + self.param_substs, + &fn_ty); + visit_fn_use(self.scx, fn_ty, false, &mut self.output); + } mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { let source_ty = operand.ty(self.mir, self.scx.tcx()); match source_ty.sty { @@ -537,111 +544,97 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_lvalue(lvalue, context, location); } - fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { - debug!("visiting operand {:?}", *operand); - - let callee = match *operand { - mir::Operand::Constant(ref constant) => { - if let ty::TyFnDef(def_id, substs, _) = constant.ty.sty { - // This is something that can act as a callee, proceed - Some((def_id, substs)) - } else { - // This is not a callee, but we still have to look for - // references to `const` items - if let mir::Literal::Item { def_id, substs } = constant.literal { - let substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &substs); - let instance = monomorphize::resolve(self.scx, def_id, substs); - collect_neighbours(self.scx, instance, self.output); - } + fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { + debug!("visiting constant {:?} @ {:?}", *constant, location); - None - } - } - _ => None - }; - - if let Some((callee_def_id, callee_substs)) = callee { - debug!(" => operand is callable"); - - // `callee_def_id` might refer to a trait method instead of a - // concrete implementation, so we have to find the actual - // implementation. For example, the call might look like - // - // std::cmp::partial_cmp(0i32, 1i32) - // - // Calling do_static_dispatch() here will map the def_id of - // `std::cmp::partial_cmp` to the def_id of `i32::partial_cmp<i32>` + if let ty::TyFnDef(..) = constant.ty.sty { + // function definitions are zero-sized, and only generate + // IR when they are called/reified. + self.super_constant(constant, location); + return + } - let callee_substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &callee_substs); - let instance = - monomorphize::resolve(self.scx, callee_def_id, callee_substs); - if should_trans_locally(self.scx.tcx(), &instance) { - if let ty::InstanceDef::ClosureOnceShim { .. } = instance.def { - // This call will instantiate an FnOnce adapter, which - // drops the closure environment. Therefore we need to - // make sure that we collect the drop-glue for the - // environment type. - - let env_ty = instance.substs.type_at(0); - let env_ty = glue::get_drop_glue_type(self.scx, env_ty); - if self.scx.type_needs_drop(env_ty) { - let dg = DropGlueKind::Ty(env_ty); - self.output.push(TransItem::DropGlue(dg)); - } - } - self.output.push(create_fn_trans_item(instance)); - } + if let mir::Literal::Item { def_id, substs } = constant.literal { + let substs = monomorphize::apply_param_substs(self.scx, + self.param_substs, + &substs); + let instance = monomorphize::resolve(self.scx, def_id, substs); + collect_neighbours(self.scx, instance, self.output); } - self.super_operand(operand, location); + self.super_constant(constant, location); } - // This takes care of the "drop_in_place" intrinsic for which we otherwise - // we would not register drop-glues. fn visit_terminator_kind(&mut self, block: mir::BasicBlock, kind: &mir::TerminatorKind<'tcx>, location: Location) { let tcx = self.scx.tcx(); - match *kind { - mir::TerminatorKind::Call { - func: mir::Operand::Constant(ref constant), - ref args, - .. - } => { - match constant.ty.sty { - ty::TyFnDef(def_id, _, bare_fn_ty) - if is_drop_in_place_intrinsic(tcx, def_id, bare_fn_ty) => { - let operand_ty = args[0].ty(self.mir, tcx); - if let ty::TyRawPtr(mt) = operand_ty.sty { - let operand_ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &mt.ty); - let ty = glue::get_drop_glue_type(self.scx, operand_ty); - self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); - } else { - bug!("Has the drop_in_place() intrinsic's signature changed?") - } - } - _ => { /* Nothing to do. */ } - } - } - _ => { /* Nothing to do. */ } + if let mir::TerminatorKind::Call { + ref func, + .. + } = *kind { + let callee_ty = func.ty(self.mir, tcx); + let callee_ty = monomorphize::apply_param_substs( + self.scx, self.param_substs, &callee_ty); + visit_fn_use(self.scx, callee_ty, true, &mut self.output); } self.super_terminator_kind(block, kind, location); + } +} + +fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + ty: ty::Ty<'tcx>, + is_direct_call: bool, + output: &mut Vec<TransItem<'tcx>>) +{ + debug!("visit_fn_use({:?}, is_direct_call={:?})", ty, is_direct_call); + let (def_id, substs) = match ty.sty { + ty::TyFnDef(def_id, substs, _) => (def_id, substs), + _ => return + }; - fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - bare_fn_ty: ty::PolyFnSig<'tcx>) - -> bool { - (bare_fn_ty.abi() == Abi::RustIntrinsic || - bare_fn_ty.abi() == Abi::PlatformIntrinsic) && - tcx.item_name(def_id) == "drop_in_place" + let instance = monomorphize::resolve(scx, def_id, substs); + if !should_trans_locally(scx.tcx(), &instance) { + return + } + + match instance.def { + ty::InstanceDef::ClosureOnceShim { .. } => { + // This call will instantiate an FnOnce adapter, which + // drops the closure environment. Therefore we need to + // make sure that we collect the drop-glue for the + // environment type along with the instance. + + let env_ty = instance.substs.type_at(0); + let env_ty = glue::get_drop_glue_type(scx, env_ty); + if scx.type_needs_drop(env_ty) { + let dg = DropGlueKind::Ty(env_ty); + output.push(TransItem::DropGlue(dg)); + } + output.push(create_fn_trans_item(instance)); + } + ty::InstanceDef::Intrinsic(..) => { + if !is_direct_call { + bug!("intrinsic {:?} being reified", ty); + } + if scx.tcx().item_name(def_id) == "drop_in_place" { + // drop_in_place is a call to drop glue, need to instantiate + // that. + let ty = glue::get_drop_glue_type(scx, substs.type_at(0)); + output.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); + } + } + ty::InstanceDef::Virtual(..) => { + // don't need to emit shim if we are calling directly. + if !is_direct_call { + output.push(create_fn_trans_item(instance)); + } + } + ty::InstanceDef::Item(..) | + ty::InstanceDef::FnPtrShim(..) => { + output.push(create_fn_trans_item(instance)); } } } @@ -657,8 +650,8 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan call_once: _, closure_did: def_id } => def_id, ty::InstanceDef::Virtual(..) | - ty::InstanceDef::FnPtrShim(..) => return true, - ty::InstanceDef::Intrinsic(_) => return false + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::Intrinsic(_) => return true }; match tcx.hir.get_if_local(def_id) { Some(hir_map::NodeForeignItem(..)) => { |
