about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-03-08 21:21:27 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-03-18 02:53:07 +0200
commita5e3c3d5b85e415ad2094f476d9f1ac29a48e413 (patch)
treee6a706d8aee71cacd92f4417e114bf22806c8576
parent65a4266f1f4ce9dac5a6ef588443b7cac911d265 (diff)
downloadrust-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.rs179
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(..)) => {