From c72240acf7a1ea107c3d995f1ca5ceb1086e7cc3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Sep 2017 08:28:17 -0700 Subject: [PATCH 01/11] rustc_trans: Refactor collection to use tcx This commit refactors the `collect_crate_translation_items` function to only require the `TyCtxt` instead of a `SharedCrateContext` in preparation for query-ifying this portion of trans. --- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/base.rs | 4 +- src/librustc_trans/callee.rs | 4 +- src/librustc_trans/collector.rs | 188 +++++++++++------------ src/librustc_trans/common.rs | 27 +++- src/librustc_trans/consts.rs | 4 +- src/librustc_trans/context.rs | 8 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/glue.rs | 11 +- src/librustc_trans/meth.rs | 2 +- src/librustc_trans/mir/block.rs | 6 +- src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans/monomorphize.rs | 51 +++--- src/librustc_trans/partitioning.rs | 2 +- src/librustc_trans/trans_item.rs | 4 +- 17 files changed, 166 insertions(+), 155 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 4211c8df5ca03..8e933d5ac8874 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -612,7 +612,7 @@ pub struct FnType<'tcx> { impl<'a, 'tcx> FnType<'tcx> { pub fn of_instance(ccx: &CrateContext<'a, 'tcx>, instance: &ty::Instance<'tcx>) -> Self { - let fn_ty = instance_ty(ccx.shared(), &instance); + let fn_ty = instance_ty(ccx.tcx(), &instance); let sig = ty_fn_sig(ccx, fn_ty); let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); Self::new(ccx, sig, &[]) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 026417682cc74..216c05b4b0a85 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -578,7 +578,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance // release builds. info!("trans_instance({})", instance); - let fn_ty = common::instance_ty(ccx.shared(), &instance); + let fn_ty = common::instance_ty(ccx.tcx(), &instance); let sig = common::ty_fn_sig(ccx, fn_ty); let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); @@ -1424,7 +1424,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a let (items, inlining_map) = time(time_passes, "translation item collection", || { - collector::collect_crate_translation_items(&scx, + collector::collect_crate_translation_items(scx.tcx(), exported_symbols, collection_mode) }); diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 246eb49ffa674..ffdd76dd68731 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -45,7 +45,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert!(!instance.substs.has_escaping_regions()); assert!(!instance.substs.has_param_types()); - let fn_ty = common::instance_ty(ccx.shared(), &instance); + let fn_ty = common::instance_ty(ccx.tcx(), &instance); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { return llfn; } @@ -148,5 +148,5 @@ pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, substs: &'tcx Substs<'tcx>) -> ValueRef { - get_fn(ccx, monomorphize::resolve(ccx.shared(), def_id, substs)) + get_fn(ccx, monomorphize::resolve(ccx.tcx(), def_id, substs)) } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index f0d8c7e9bfbca..bda035fc343c8 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -202,8 +202,7 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::mir::{self, Location}; use rustc::mir::visit::Visitor as MirVisitor; -use context::SharedCrateContext; -use common::{def_ty, instance_ty}; +use common::{def_ty, instance_ty, type_is_sized}; use monomorphize::{self, Instance}; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; @@ -294,15 +293,15 @@ impl<'tcx> InliningMap<'tcx> { } } -pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +pub fn collect_crate_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, exported_symbols: &ExportedSymbols, mode: TransItemCollectionMode) -> (FxHashSet>, InliningMap<'tcx>) { // We are not tracking dependencies of this pass as it has to be re-executed // every time no matter what. - scx.tcx().dep_graph.with_ignore(|| { - let roots = collect_roots(scx, exported_symbols, mode); + tcx.dep_graph.with_ignore(|| { + let roots = collect_roots(tcx, exported_symbols, mode); debug!("Building translation item graph, beginning at roots"); let mut visited = FxHashSet(); @@ -310,7 +309,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 't let mut inlining_map = InliningMap::new(); for root in roots { - collect_items_rec(scx, + collect_items_rec(tcx, root, &mut visited, &mut recursion_depths, @@ -323,7 +322,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 't // Find all non-generic items by walking the HIR. These items serve as roots to // start monomorphizing from. -fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, exported_symbols: &ExportedSymbols, mode: TransItemCollectionMode) -> Vec> { @@ -332,25 +331,25 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, { let mut visitor = RootCollector { - scx, + tcx, mode, exported_symbols, output: &mut roots, }; - scx.tcx().hir.krate().visit_all_item_likes(&mut visitor); + tcx.hir.krate().visit_all_item_likes(&mut visitor); } // We can only translate items that are instantiable - items all of // whose predicates hold. Luckily, items that aren't instantiable // can't actually be used, so we can just skip translating them. - roots.retain(|root| root.is_instantiable(scx.tcx())); + roots.retain(|root| root.is_instantiable(tcx)); roots } // Collect all monomorphized translation items reachable from `starting_point` -fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, +fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, starting_point: TransItem<'tcx>, visited: &mut FxHashSet>, recursion_depths: &mut DefIdMap, @@ -359,54 +358,54 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, // We've been here already, no need to search again. return; } - debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx.tcx())); + debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx)); let mut neighbors = Vec::new(); let recursion_depth_reset; match starting_point { TransItem::Static(node_id) => { - let def_id = scx.tcx().hir.local_def_id(node_id); - let instance = Instance::mono(scx.tcx(), def_id); + let def_id = tcx.hir.local_def_id(node_id); + let instance = Instance::mono(tcx, def_id); // Sanity check whether this ended up being collected accidentally - debug_assert!(should_trans_locally(scx.tcx(), &instance)); + debug_assert!(should_trans_locally(tcx, &instance)); - let ty = instance_ty(scx, &instance); - visit_drop_use(scx, ty, true, &mut neighbors); + let ty = instance_ty(tcx, &instance); + visit_drop_use(tcx, ty, true, &mut neighbors); recursion_depth_reset = None; - collect_neighbours(scx, instance, true, &mut neighbors); + collect_neighbours(tcx, instance, true, &mut neighbors); } TransItem::Fn(instance) => { // Sanity check whether this ended up being collected accidentally - debug_assert!(should_trans_locally(scx.tcx(), &instance)); + debug_assert!(should_trans_locally(tcx, &instance)); // Keep track of the monomorphization recursion depth - recursion_depth_reset = Some(check_recursion_limit(scx.tcx(), + recursion_depth_reset = Some(check_recursion_limit(tcx, instance, recursion_depths)); - check_type_length_limit(scx.tcx(), instance); + check_type_length_limit(tcx, instance); - collect_neighbours(scx, instance, false, &mut neighbors); + collect_neighbours(tcx, instance, false, &mut neighbors); } TransItem::GlobalAsm(..) => { recursion_depth_reset = None; } } - record_accesses(scx.tcx(), starting_point, &neighbors[..], inlining_map); + record_accesses(tcx, starting_point, &neighbors[..], inlining_map); for neighbour in neighbors { - collect_items_rec(scx, neighbour, visited, recursion_depths, inlining_map); + collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map); } if let Some((def_id, depth)) = recursion_depth_reset { recursion_depths.insert(def_id, depth); } - debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx())); + debug!("END collect_items_rec({})", starting_point.to_string(tcx)); } fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -494,7 +493,7 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } struct MirNeighborCollector<'a, 'tcx: 'a> { - scx: &'a SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a mir::Mir<'tcx>, output: &'a mut Vec>, param_substs: &'tcx Substs<'tcx>, @@ -511,49 +510,49 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { - let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &target_ty); - let source_ty = operand.ty(self.mir, self.scx.tcx()); - let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &source_ty); - let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, + let target_ty = self.tcx.trans_apply_param_substs(self.param_substs, + &target_ty); + let source_ty = operand.ty(self.mir, self.tcx); + let source_ty = self.tcx.trans_apply_param_substs(self.param_substs, + &source_ty); + let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.tcx, source_ty, target_ty); // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. if target_ty.is_trait() && !source_ty.is_trait() { - create_trans_items_for_vtable_methods(self.scx, + create_trans_items_for_vtable_methods(self.tcx, target_ty, source_ty, self.output); } } mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => { - let fn_ty = operand.ty(self.mir, self.scx.tcx()); - let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &fn_ty); - visit_fn_use(self.scx, fn_ty, false, &mut self.output); + let fn_ty = operand.ty(self.mir, self.tcx); + let fn_ty = self.tcx.trans_apply_param_substs(self.param_substs, + &fn_ty); + visit_fn_use(self.tcx, fn_ty, false, &mut self.output); } mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { - let source_ty = operand.ty(self.mir, self.scx.tcx()); - let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &source_ty); + let source_ty = operand.ty(self.mir, self.tcx); + let source_ty = self.tcx.trans_apply_param_substs(self.param_substs, + &source_ty); match source_ty.sty { ty::TyClosure(def_id, substs) => { let instance = monomorphize::resolve_closure( - self.scx, def_id, substs, ty::ClosureKind::FnOnce); + self.tcx, def_id, substs, ty::ClosureKind::FnOnce); self.output.push(create_fn_trans_item(instance)); } _ => bug!(), } } mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { - let tcx = self.scx.tcx(); + let tcx = self.tcx; let exchange_malloc_fn_def_id = tcx .lang_items() .require(ExchangeMallocFnLangItem) - .unwrap_or_else(|e| self.scx.sess().fatal(&e)); + .unwrap_or_else(|e| tcx.sess.fatal(&e)); let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); if should_trans_locally(tcx, &instance) { self.output.push(create_fn_trans_item(instance)); @@ -569,10 +568,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { debug!("visiting const {:?} @ {:?}", *constant, location); if let ConstVal::Unevaluated(def_id, substs) = constant.val { - let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &substs); - let instance = monomorphize::resolve(self.scx, def_id, substs); - collect_neighbours(self.scx, instance, true, self.output); + let substs = self.tcx.trans_apply_param_substs(self.param_substs, + &substs); + let instance = monomorphize::resolve(self.tcx, def_id, substs); + collect_neighbours(self.tcx, instance, true, self.output); } self.super_const(constant); @@ -584,15 +583,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { location: Location) { debug!("visiting terminator {:?} @ {:?}", kind, location); - let tcx = self.scx.tcx(); + let tcx = self.tcx; match *kind { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.mir, tcx); let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty); let constness = match (self.const_context, &callee_ty.sty) { - (true, &ty::TyFnDef(def_id, substs)) if self.scx.tcx().is_const_fn(def_id) => { - let instance = monomorphize::resolve(self.scx, def_id, substs); + (true, &ty::TyFnDef(def_id, substs)) if self.tcx.is_const_fn(def_id) => { + let instance = monomorphize::resolve(self.tcx, def_id, substs); Some(instance) } _ => None @@ -602,20 +601,20 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // If this is a const fn, called from a const context, we // have to visit its body in order to find any fn reifications // it might contain. - collect_neighbours(self.scx, + collect_neighbours(self.tcx, const_fn_instance, true, self.output); } else { - visit_fn_use(self.scx, callee_ty, true, &mut self.output); + visit_fn_use(self.tcx, callee_ty, true, &mut self.output); } } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { - let ty = location.ty(self.mir, self.scx.tcx()) - .to_ty(self.scx.tcx()); + let ty = location.ty(self.mir, self.tcx) + .to_ty(self.tcx); let ty = tcx.trans_apply_param_substs(self.param_substs, &ty); - visit_drop_use(self.scx, ty, true, self.output); + visit_drop_use(self.tcx, ty, true, self.output); } mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::SwitchInt { .. } | @@ -636,7 +635,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { location: Location) { debug!("visiting static {:?} @ {:?}", static_.def_id, location); - let tcx = self.scx.tcx(); + let tcx = self.tcx; let instance = Instance::mono(tcx, static_.def_id); if should_trans_locally(tcx, &instance) { let node_id = tcx.hir.as_local_node_id(static_.def_id).unwrap(); @@ -647,33 +646,33 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } } -fn visit_drop_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn visit_drop_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, is_direct_call: bool, output: &mut Vec>) { - let instance = monomorphize::resolve_drop_in_place(scx, ty); - visit_instance_use(scx, instance, is_direct_call, output); + let instance = monomorphize::resolve_drop_in_place(tcx, ty); + visit_instance_use(tcx, instance, is_direct_call, output); } -fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, is_direct_call: bool, output: &mut Vec>) { if let ty::TyFnDef(def_id, substs) = ty.sty { - let instance = monomorphize::resolve(scx, def_id, substs); - visit_instance_use(scx, instance, is_direct_call, output); + let instance = monomorphize::resolve(tcx, def_id, substs); + visit_instance_use(tcx, instance, is_direct_call, output); } } -fn visit_instance_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn visit_instance_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: ty::Instance<'tcx>, is_direct_call: bool, output: &mut Vec>) { debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); - if !should_trans_locally(scx.tcx(), &instance) { + if !should_trans_locally(tcx, &instance) { return } @@ -775,15 +774,15 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan /// /// Finally, there is also the case of custom unsizing coercions, e.g. for /// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { - if !scx.type_is_sized(inner_source) { + if !type_is_sized(tcx, inner_source) { (inner_source, inner_target) } else { - scx.tcx().struct_lockstep_tails(inner_source, inner_target) + tcx.struct_lockstep_tails(inner_source, inner_target) } }; match (&source_ty.sty, &target_ty.sty) { @@ -804,7 +803,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, assert_eq!(source_adt_def, target_adt_def); let kind = - monomorphize::custom_coerce_unsize_info(scx, source_ty, target_ty); + monomorphize::custom_coerce_unsize_info(tcx, source_ty, target_ty); let coerce_index = match kind { CustomCoerceUnsized::Struct(i) => i @@ -816,10 +815,10 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, assert!(coerce_index < source_fields.len() && source_fields.len() == target_fields.len()); - find_vtable_types_for_unsizing(scx, - source_fields[coerce_index].ty(scx.tcx(), + find_vtable_types_for_unsizing(tcx, + source_fields[coerce_index].ty(tcx, source_substs), - target_fields[coerce_index].ty(scx.tcx(), + target_fields[coerce_index].ty(tcx, target_substs)) } _ => bug!("find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", @@ -835,7 +834,7 @@ fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> { /// Creates a `TransItem` for each method that is referenced by the vtable for /// the given trait/impl pair. -fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ty: Ty<'tcx>, impl_ty: Ty<'tcx>, output: &mut Vec>) { @@ -844,19 +843,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, if let ty::TyDynamic(ref trait_ty, ..) = trait_ty.sty { if let Some(principal) = trait_ty.principal() { - let poly_trait_ref = principal.with_self_ty(scx.tcx(), impl_ty); + let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); assert!(!poly_trait_ref.has_escaping_regions()); // Walk all methods of the trait, including those of its supertraits - let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref); + let methods = traits::get_vtable_methods(tcx, poly_trait_ref); let methods = methods.filter_map(|method| method) - .map(|(def_id, substs)| monomorphize::resolve(scx, def_id, substs)) - .filter(|&instance| should_trans_locally(scx.tcx(), &instance)) + .map(|(def_id, substs)| monomorphize::resolve(tcx, def_id, substs)) + .filter(|&instance| should_trans_locally(tcx, &instance)) .map(|instance| create_fn_trans_item(instance)); output.extend(methods); } // Also add the destructor - visit_drop_use(scx, impl_ty, false, output); + visit_drop_use(tcx, impl_ty, false, output); } } @@ -865,7 +864,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, //=----------------------------------------------------------------------------- struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { - scx: &'b SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, exported_symbols: &'b ExportedSymbols, mode: TransItemCollectionMode, output: &'b mut Vec>, @@ -886,7 +885,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemImpl(..) => { if self.mode == TransItemCollectionMode::Eager { - create_trans_items_for_default_impls(self.scx, + create_trans_items_for_default_impls(self.tcx, item, self.output); } @@ -897,25 +896,25 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemUnion(_, ref generics) => { if !generics.is_parameterized() { if self.mode == TransItemCollectionMode::Eager { - let def_id = self.scx.tcx().hir.local_def_id(item.id); + let def_id = self.tcx.hir.local_def_id(item.id); debug!("RootCollector: ADT drop-glue for {}", - def_id_to_string(self.scx.tcx(), def_id)); + def_id_to_string(self.tcx, def_id)); - let ty = def_ty(self.scx, def_id, Substs::empty()); - visit_drop_use(self.scx, ty, true, self.output); + let ty = def_ty(self.tcx, def_id, Substs::empty()); + visit_drop_use(self.tcx, ty, true, self.output); } } } hir::ItemGlobalAsm(..) => { debug!("RootCollector: ItemGlobalAsm({})", - def_id_to_string(self.scx.tcx(), - self.scx.tcx().hir.local_def_id(item.id))); + def_id_to_string(self.tcx, + self.tcx.hir.local_def_id(item.id))); self.output.push(TransItem::GlobalAsm(item.id)); } hir::ItemStatic(..) => { debug!("RootCollector: ItemStatic({})", - def_id_to_string(self.scx.tcx(), - self.scx.tcx().hir.local_def_id(item.id))); + def_id_to_string(self.tcx, + self.tcx.hir.local_def_id(item.id))); self.output.push(TransItem::Static(item.id)); } hir::ItemConst(..) => { @@ -923,7 +922,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { // actually used somewhere. Just declaring them is insufficient. } hir::ItemFn(..) => { - let tcx = self.scx.tcx(); + let tcx = self.tcx; let def_id = tcx.hir.local_def_id(item.id); if (self.mode == TransItemCollectionMode::Eager || @@ -949,7 +948,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { match ii.node { hir::ImplItemKind::Method(hir::MethodSig { .. }, _) => { - let tcx = self.scx.tcx(); + let tcx = self.tcx; let def_id = tcx.hir.local_def_id(ii.id); if (self.mode == TransItemCollectionMode::Eager || @@ -973,10 +972,9 @@ fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId generics.parent_types as usize + generics.types.len() > 0 } -fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &'tcx hir::Item, output: &mut Vec>) { - let tcx = scx.tcx(); match item.node { hir::ItemImpl(_, _, @@ -1009,7 +1007,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' } let instance = - monomorphize::resolve(scx, method.def_id, callee_substs); + monomorphize::resolve(tcx, method.def_id, callee_substs); let trans_item = create_fn_trans_item(instance); if trans_item.is_instantiable(tcx) && should_trans_locally(tcx, &instance) { @@ -1025,15 +1023,15 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' } /// Scan the MIR in order to find function calls, closures, and drop-glue -fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, const_context: bool, output: &mut Vec>) { - let mir = scx.tcx().instance_mir(instance.def); + let mir = tcx.instance_mir(instance.def); let mut visitor = MirNeighborCollector { - scx, + tcx, mir: &mir, output, param_substs: instance.substs, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 67c95b92e523b..52607904f73c4 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -26,6 +26,7 @@ use machine; use monomorphize; use type_::Type; use value::Value; +use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{Layout, LayoutTyper}; use rustc::ty::subst::{Kind, Subst, Substs}; @@ -37,7 +38,7 @@ use std::iter; use syntax::abi::Abi; use syntax::attr; use syntax::symbol::InternedString; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; pub use context::{CrateContext, SharedCrateContext}; @@ -140,6 +141,18 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - !layout.is_unsized() && layout.size(ccx).bytes() == 0 } +pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All)) +} + +pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) +} + +pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_freeze(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) +} + /* * A note on nomenclature of linking: "extern", "foreign", and "upcall". * @@ -573,20 +586,20 @@ pub fn is_inline_instance<'a, 'tcx>( } /// Given a DefId and some Substs, produces the monomorphic item type. -pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, +pub fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - let ty = shared.tcx().type_of(def_id); - shared.tcx().trans_apply_param_substs(substs, &ty) + let ty = tcx.type_of(def_id); + tcx.trans_apply_param_substs(substs, &ty) } /// Return the substituted type of an instance. -pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, +pub fn instance_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &ty::Instance<'tcx>) -> Ty<'tcx> { - let ty = instance.def.def_ty(shared.tcx()); - shared.tcx().trans_apply_param_substs(instance.substs, &ty) + let ty = instance.def.def_ty(tcx); + tcx.trans_apply_param_substs(instance.substs, &ty) } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index bad8a8655d093..a566cddde566b 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -109,7 +109,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { return g; } - let ty = common::instance_ty(ccx.shared(), &instance); + let ty = common::instance_ty(ccx.tcx(), &instance); let g = if let Some(id) = ccx.tcx().hir.as_local_node_id(def_id) { let llty = type_of::type_of(ccx, ty); @@ -269,7 +269,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; let instance = Instance::mono(ccx.tcx(), def_id); - let ty = common::instance_ty(ccx.shared(), &instance); + let ty = common::instance_ty(ccx.tcx(), &instance); let llty = type_of::type_of(ccx, ty); let g = if val_llty == llty { g diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 4211be362ef19..3ad96d482f116 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use common; use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; use rustc::dep_graph::{DepGraph, DepGraphSafe}; @@ -39,7 +40,6 @@ use std::str; use std::sync::Arc; use std::marker::PhantomData; use syntax::symbol::InternedString; -use syntax_pos::DUMMY_SP; use abi::Abi; #[derive(Clone, Default)] @@ -319,15 +319,15 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { } pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - ty.needs_drop(self.tcx, ty::ParamEnv::empty(traits::Reveal::All)) + common::type_needs_drop(self.tcx, ty) } pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) + common::type_is_sized(self.tcx, ty) } pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) + common::type_is_freeze(self.tcx, ty) } pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 3c87bc293b5b5..333f7b1c029c1 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1803,7 +1803,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let variable_type = common::def_ty(cx.shared(), node_def_id, Substs::empty()); + let variable_type = common::def_ty(cx.tcx(), node_def_id, Substs::empty()); let type_metadata = type_metadata(cx, variable_type, span); let var_name = tcx.item_name(node_def_id).to_string(); let linkage_name = mangled_name_of_item(cx, node_def_id, ""); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 83366c13453bc..7e2ac95cd845c 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -428,7 +428,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // If the method does *not* belong to a trait, proceed if cx.tcx().trait_id_of_impl(impl_def_id).is_none() { let impl_self_ty = - common::def_ty(cx.shared(), impl_def_id, instance.substs); + common::def_ty(cx.tcx(), impl_def_id, instance.substs); // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g. `<*mut T>::null`). diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 3939497971337..1572f1dc230c1 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -14,15 +14,16 @@ use std; -use llvm; -use llvm::{ValueRef}; -use rustc::ty::{self, Ty}; -use rustc::ty::layout::LayoutTyper; +use builder::Builder; use common::*; +use llvm::{ValueRef}; +use llvm; use meth; use monomorphize; +use rustc::traits; +use rustc::ty::layout::LayoutTyper; +use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; use value::Value; -use builder::Builder; pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef) -> (ValueRef, ValueRef) { diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 9abfbb3279ce0..88407947f0ef4 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -80,7 +80,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let nullptr = C_null(Type::nil(ccx).ptr_to()); let mut components: Vec<_> = [ - callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)), + callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.tcx(), ty)), C_usize(ccx, ccx.size_of(ty)), C_usize(ccx, ccx.align_of(ty) as u64) ].iter().cloned().collect(); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 1105da436189f..9246822b33920 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -265,7 +265,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::TerminatorKind::Drop { ref location, target, unwind } => { let ty = location.ty(self.mir, bcx.tcx()).to_ty(bcx.tcx()); let ty = self.monomorphize(&ty); - let drop_fn = monomorphize::resolve_drop_in_place(bcx.ccx.shared(), ty); + let drop_fn = monomorphize::resolve_drop_in_place(bcx.ccx.tcx(), ty); if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { // we don't actually need to drop anything. @@ -429,7 +429,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let (instance, mut llfn) = match callee.ty.sty { ty::TyFnDef(def_id, substs) => { - (Some(monomorphize::resolve(bcx.ccx.shared(), def_id, substs)), + (Some(monomorphize::resolve(bcx.ccx.tcx(), def_id, substs)), None) } ty::TyFnPtr(_) => { @@ -546,7 +546,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }; let callee_ty = common::instance_ty( - bcx.ccx.shared(), instance.as_ref().unwrap()); + bcx.ccx.tcx(), instance.as_ref().unwrap()); trans_intrinsic_call(&bcx, callee_ty, &fn_ty, &llargs, dest, terminator.source_info.span); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 4c3326a466d3a..9232d73f832e7 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -261,7 +261,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { substs: &'tcx Substs<'tcx>, args: IndexVec, ConstEvalErr<'tcx>>>) -> Result, ConstEvalErr<'tcx>> { - let instance = monomorphize::resolve(ccx.shared(), def_id, substs); + let instance = monomorphize::resolve(ccx.tcx(), def_id, substs); let mir = ccx.tcx().instance_mir(instance.def); MirConstContext::new(ccx, &mir, instance.substs, args).trans() } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 20ed4ab50a00f..822431eba42f1 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -222,7 +222,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { match operand.ty.sty { ty::TyClosure(def_id, substs) => { let instance = monomorphize::resolve_closure( - bcx.ccx.shared(), def_id, substs, ty::ClosureKind::FnOnce); + bcx.ccx.tcx(), def_id, substs, ty::ClosureKind::FnOnce); OperandValue::Immediate(callee::get_fn(bcx.ccx, instance)) } _ => { diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 309177d9ff6a2..e62924a54d757 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -85,27 +85,26 @@ fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, } pub fn resolve_closure<'a, 'tcx> ( - scx: &SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: ty::ClosureSubsts<'tcx>, requested_kind: ty::ClosureKind) -> Instance<'tcx> { - let actual_kind = scx.tcx().closure_kind(def_id); + let actual_kind = tcx.closure_kind(def_id); match needs_fn_once_adapter_shim(actual_kind, requested_kind) { - Ok(true) => fn_once_adapter_instance(scx.tcx(), def_id, substs), + Ok(true) => fn_once_adapter_instance(tcx, def_id, substs), _ => Instance::new(def_id, substs.substs) } } fn resolve_associated_item<'a, 'tcx>( - scx: &SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &ty::AssociatedItem, trait_id: DefId, rcvr_substs: &'tcx Substs<'tcx> ) -> Instance<'tcx> { - let tcx = scx.tcx(); let def_id = trait_item.def_id; debug!("resolve_associated_item(trait_item={:?}, \ trait_id={:?}, \ @@ -132,7 +131,7 @@ fn resolve_associated_item<'a, 'tcx>( } traits::VtableClosure(closure_data) => { let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap(); - resolve_closure(scx, closure_data.closure_def_id, closure_data.substs, + resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs, trait_closure_kind) } traits::VtableFnPointer(ref data) => { @@ -163,21 +162,21 @@ fn resolve_associated_item<'a, 'tcx>( /// The point where linking happens. Resolve a (def_id, substs) /// pair to an instance. pub fn resolve<'a, 'tcx>( - scx: &SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx> ) -> Instance<'tcx> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - let result = if let Some(trait_def_id) = scx.tcx().trait_of_item(def_id) { + let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { debug!(" => associated item, attempting to find impl"); - let item = scx.tcx().associated_item(def_id); - resolve_associated_item(scx, &item, trait_def_id, substs) + let item = tcx.associated_item(def_id); + resolve_associated_item(tcx, &item, trait_def_id, substs) } else { - let item_type = def_ty(scx, def_id, substs); + let item_type = def_ty(tcx, def_id, substs); let def = match item_type.sty { ty::TyFnDef(..) if { - let f = item_type.fn_sig(scx.tcx()); + let f = item_type.fn_sig(tcx); f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic } => @@ -186,9 +185,9 @@ pub fn resolve<'a, 'tcx>( ty::InstanceDef::Intrinsic(def_id) } _ => { - if Some(def_id) == scx.tcx().lang_items().drop_in_place_fn() { + if Some(def_id) == tcx.lang_items().drop_in_place_fn() { let ty = substs.type_at(0); - if scx.type_needs_drop(ty) { + if common::type_needs_drop(tcx, ty) { debug!(" => nontrivial drop glue"); ty::InstanceDef::DropGlue(def_id, Some(ty)) } else { @@ -209,27 +208,27 @@ pub fn resolve<'a, 'tcx>( } pub fn resolve_drop_in_place<'a, 'tcx>( - scx: &SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = scx.tcx().require_lang_item(DropInPlaceFnLangItem); - let substs = scx.tcx().intern_substs(&[Kind::from(ty)]); - resolve(scx, def_id, substs) + let def_id = tcx.require_lang_item(DropInPlaceFnLangItem); + let substs = tcx.intern_substs(&[Kind::from(ty)]); + resolve(tcx, def_id, substs) } -pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>, - source_ty: Ty<'tcx>, - target_ty: Ty<'tcx>) - -> CustomCoerceUnsized { +pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + source_ty: Ty<'tcx>, + target_ty: Ty<'tcx>) + -> CustomCoerceUnsized { let trait_ref = ty::Binder(ty::TraitRef { - def_id: scx.tcx().lang_items().coerce_unsized_trait().unwrap(), - substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) + def_id: tcx.lang_items().coerce_unsized_trait().unwrap(), + substs: tcx.mk_substs_trait(source_ty, &[target_ty]) }); - match scx.tcx().trans_fulfill_obligation(DUMMY_SP, trait_ref) { + match tcx.trans_fulfill_obligation(DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { - scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap() + tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap() } vtable => { bug!("invalid CoerceUnsized vtable: {:?}", vtable); diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 26256fa78dd4d..782a00648ce21 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -621,7 +621,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't if let Some(impl_def_id) = tcx.impl_of_method(def_id) { // This is a method within an inherent impl, find out what the // self-type is: - let impl_self_ty = common::def_ty(scx, impl_def_id, instance.substs); + let impl_self_ty = common::def_ty(scx.tcx(), impl_def_id, instance.substs); if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { return Some(def_id); } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 1f27eb9fcb309..5a51f690c45f1 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> TransItem<'tcx> { symbol_name: &str) { let def_id = ccx.tcx().hir.local_def_id(node_id); let instance = Instance::mono(ccx.tcx(), def_id); - let ty = common::instance_ty(ccx.shared(), &instance); + let ty = common::instance_ty(ccx.tcx(), &instance); let llty = type_of::type_of(ccx, ty); let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { @@ -158,7 +158,7 @@ impl<'a, 'tcx> TransItem<'tcx> { assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types()); - let mono_ty = common::instance_ty(ccx.shared(), &instance); + let mono_ty = common::instance_ty(ccx.tcx(), &instance); let attrs = instance.def.attrs(ccx.tcx()); let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); unsafe { llvm::LLVMRustSetLinkage(lldecl, linkage) }; From a97ad6ae50e8ce02acaa3153312d0448e98b7d2f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Sep 2017 08:32:50 -0700 Subject: [PATCH 02/11] rustc: Refactor trans paritioning to use tcx This commit refactors the the `partitioning::partition` function to operate with a `TyCtxt` instead of a `SharedCrateContext` in preparation for making it a query. --- src/librustc_trans/base.rs | 2 +- src/librustc_trans/partitioning.rs | 20 ++++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 216c05b4b0a85..507287756b8c2 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1438,7 +1438,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a }; let codegen_units = time(time_passes, "codegen unit partitioning", || { - partitioning::partition(scx, + partitioning::partition(scx.tcx(), items.iter().cloned(), strategy, &inlining_map, diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 782a00648ce21..d436d0d8b6a27 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -221,7 +221,7 @@ impl<'tcx> CodegenUnit<'tcx> { // Anything we can't find a proper codegen unit for goes into this. const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; -pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, +pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I, strategy: PartitioningStrategy, inlining_map: &InliningMap<'tcx>, @@ -229,12 +229,10 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, -> Vec> where I: Iterator> { - let tcx = scx.tcx(); - // In the first step, we place all regular translation items into their // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. - let mut initial_partitioning = place_root_translation_items(scx, + let mut initial_partitioning = place_root_translation_items(tcx, exported_symbols, trans_items); @@ -272,10 +270,10 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, (&cgu1.name[..]).cmp(&cgu2.name[..]) }); - if scx.sess().opts.enable_dep_node_debug_strs() { + if tcx.sess.opts.enable_dep_node_debug_strs() { for cgu in &result { let dep_node = cgu.work_product_dep_node(); - scx.tcx().dep_graph.register_dep_node_debug_str(dep_node, + tcx.dep_graph.register_dep_node_debug_str(dep_node, || cgu.name().to_string()); } } @@ -304,13 +302,12 @@ struct PostInliningPartitioning<'tcx> { internalization_candidates: FxHashSet>, } -fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, +fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, exported_symbols: &ExportedSymbols, trans_items: I) -> PreInliningPartitioning<'tcx> where I: Iterator> { - let tcx = scx.tcx(); let exported_symbols = exported_symbols.local_exports(); let mut roots = FxHashSet(); @@ -322,7 +319,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let is_root = trans_item.instantiation_mode(tcx) == InstantiationMode::GloballyShared; if is_root { - let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item); + let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item); let is_volatile = is_incremental_build && trans_item.is_generic_fn(); @@ -592,10 +589,9 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_item: TransItem<'tcx>) -> Option { - let tcx = scx.tcx(); match trans_item { TransItem::Fn(instance) => { let def_id = match instance.def { @@ -621,7 +617,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't if let Some(impl_def_id) = tcx.impl_of_method(def_id) { // This is a method within an inherent impl, find out what the // self-type is: - let impl_self_ty = common::def_ty(scx.tcx(), impl_def_id, instance.substs); + let impl_self_ty = common::def_ty(tcx, impl_def_id, instance.substs); if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { return Some(def_id); } From baca9a6240115996d35336f5bb7d78e60babd722 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Sep 2017 09:04:24 -0700 Subject: [PATCH 03/11] rustc: Use reachablility through a query Turns out this was already set up as a query, just wasn't using it yet! --- src/librustc/middle/reachable.rs | 4 ---- src/librustc/ty/mod.rs | 1 - src/librustc_driver/driver.rs | 12 ++---------- src/librustc_trans/base.rs | 8 +++----- 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index d3e34c851f3d6..a04ecefce0f36 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -369,10 +369,6 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } } -pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { - tcx.reachable_set(LOCAL_CRATE) -} - fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc { debug_assert!(crate_num == LOCAL_CRATE); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2d5b0ce0954fc..e2df963f80fad 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -121,7 +121,6 @@ mod sty; #[derive(Clone)] pub struct CrateAnalysis { pub access_levels: Rc, - pub reachable: Rc, pub name: String, pub glob_map: Option, } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ed012f87996d7..b01179c43111b 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -28,7 +28,6 @@ use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes}; use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas}; use rustc::traits; use rustc::util::common::{ErrorReported, time}; -use rustc::util::nodemap::NodeSet; use rustc_allocator as allocator; use rustc_borrowck as borrowck; use rustc_incremental::{self, IncrementalHashesMap}; @@ -243,7 +242,7 @@ pub fn compile_input(sess: &Session, tcx.print_debug_stats(); } - let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map, + let trans = phase_4_translate_to_llvm(tcx, incremental_hashes_map, &outputs); if log_enabled!(::log::LogLevel::Info) { @@ -885,7 +884,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, defs: resolver.definitions, analysis: ty::CrateAnalysis { access_levels: Rc::new(AccessLevels::default()), - reachable: Rc::new(NodeSet()), name: crate_name.to_string(), glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, }, @@ -1103,11 +1101,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, return Ok(f(tcx, analysis, incremental_hashes_map, sess.compile_status())); } - analysis.reachable = - time(time_passes, - "reachability checking", - || reachable::find_reachable(tcx)); - time(time_passes, "death checking", || middle::dead::check_crate(tcx)); time(time_passes, "unused lib feature checking", || { @@ -1123,7 +1116,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, /// Run the translation phase to LLVM, after which the AST and analysis can /// be discarded. pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - analysis: ty::CrateAnalysis, incremental_hashes_map: IncrementalHashesMap, output_filenames: &OutputFilenames) -> write::OngoingCrateTranslation { @@ -1136,7 +1128,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let translation = time(time_passes, "translation", - move || trans::trans_crate(tcx, analysis, incremental_hashes_map, output_filenames)); + move || trans::trans_crate(tcx, incremental_hashes_map, output_filenames)); if tcx.sess.profile_queries() { profile::dump("profile_queries".to_string()) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 507287756b8c2..1ea38eadb759c 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -886,8 +886,8 @@ fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter { /// /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { - reachable.iter().cloned().filter(|&id| { +pub fn find_exported_symbols(tcx: TyCtxt) -> NodeSet { + tcx.reachable_set(LOCAL_CRATE).iter().cloned().filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two // categories: @@ -929,7 +929,6 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { } pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - analysis: ty::CrateAnalysis, incremental_hashes_map: IncrementalHashesMap, output_filenames: &OutputFilenames) -> OngoingCrateTranslation { @@ -940,10 +939,9 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // `TransCrate`, you need to be careful to register "reads" of the // particular items that will be processed. let krate = tcx.hir.krate(); - let ty::CrateAnalysis { reachable, .. } = analysis; let check_overflow = tcx.sess.overflow_checks(); let link_meta = link::build_link_meta(&incremental_hashes_map); - let exported_symbol_node_ids = find_exported_symbols(tcx, &reachable); + let exported_symbol_node_ids = find_exported_symbols(tcx); let shared_ccx = SharedCrateContext::new(tcx, check_overflow, From dba3ddd8d4e037db390f54536b4cb77ea988eab1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Sep 2017 09:32:37 -0700 Subject: [PATCH 04/11] rustc: Calculate `ExportedSymbols` in a query This commit moves the definition of the `ExportedSymbols` structure to the `rustc` crate and then creates a query that'll be used to construct the `ExportedSymbols` set. This in turn uses the reachablity query exposed in the previous commit. --- src/librustc/dep_graph/dep_node.rs | 3 +- src/librustc/lib.rs | 1 + src/librustc/middle/exported_symbols.rs | 77 ++++++ src/librustc/ty/context.rs | 6 + src/librustc/ty/maps.rs | 19 +- src/librustc_driver/driver.rs | 4 +- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_trans/back/linker.rs | 2 +- src/librustc_trans/back/lto.rs | 3 +- src/librustc_trans/back/symbol_export.rs | 297 +++++++++-------------- src/librustc_trans/back/write.rs | 2 +- src/librustc_trans/base.rs | 40 +-- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/context.rs | 2 +- src/librustc_trans/lib.rs | 19 +- src/librustc_trans/partitioning.rs | 2 +- 16 files changed, 266 insertions(+), 215 deletions(-) create mode 100644 src/librustc/middle/exported_symbols.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 27561bddd295b..757a256164e08 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -535,7 +535,7 @@ define_dep_nodes!( <'tcx> [] GetPanicStrategy(CrateNum), [] IsNoBuiltins(CrateNum), [] ImplDefaultness(DefId), - [] ExportedSymbols(CrateNum), + [] ExportedSymbolIds(CrateNum), [] NativeLibraries(CrateNum), [] PluginRegistrarFn(CrateNum), [] DeriveRegistrarFn(CrateNum), @@ -575,6 +575,7 @@ define_dep_nodes!( <'tcx> [] MaybeUnusedExternCrates, [] StabilityIndex, [] AllCrateNums, + [] ExportedSymbols, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index df97f2fb8bcd6..59edc9fb083ac 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -92,6 +92,7 @@ pub mod middle { pub mod dependency_format; pub mod effect; pub mod entry; + pub mod exported_symbols; pub mod free_region; pub mod intrinsicck; pub mod lang_items; diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs new file mode 100644 index 0000000000000..7f03f8a5a2986 --- /dev/null +++ b/src/librustc/middle/exported_symbols.rs @@ -0,0 +1,77 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use util::nodemap::{FxHashMap, NodeSet}; +use hir::def_id::{DefId, CrateNum}; + +/// The SymbolExportLevel of a symbols specifies from which kinds of crates +/// the symbol will be exported. `C` symbols will be exported from any +/// kind of crate, including cdylibs which export very few things. +/// `Rust` will only be exported if the crate produced is a Rust +/// dylib. +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum SymbolExportLevel { + C, + Rust, +} + +/// The set of symbols exported from each crate in the crate graph. +#[derive(Debug)] +pub struct ExportedSymbols { + pub export_threshold: SymbolExportLevel, + exports: FxHashMap>, + local_exports: NodeSet, +} + +impl ExportedSymbols { + pub fn new(export_threshold: SymbolExportLevel, + exports: FxHashMap>, + local_exports: NodeSet) -> ExportedSymbols { + ExportedSymbols { + export_threshold, + exports, + local_exports, + } + } + + pub fn local_exports(&self) -> &NodeSet { + &self.local_exports + } + + pub fn exported_symbols(&self, cnum: CrateNum) + -> &[(String, DefId, SymbolExportLevel)] + { + match self.exports.get(&cnum) { + Some(exports) => exports, + None => &[] + } + } + + pub fn for_each_exported_symbol(&self, cnum: CrateNum, mut f: F) + where F: FnMut(&str, DefId, SymbolExportLevel) + { + for &(ref name, def_id, export_level) in self.exported_symbols(cnum) { + if is_below_threshold(export_level, self.export_threshold) { + f(&name, def_id, export_level) + } + } + } +} + +pub fn is_below_threshold(level: SymbolExportLevel, + threshold: SymbolExportLevel) + -> bool { + if threshold == SymbolExportLevel::Rust { + // We export everything from Rust dylibs + true + } else { + level == SymbolExportLevel::C + } +} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fb0cdab0b6a0f..af5c37e0f1605 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -27,6 +27,7 @@ use middle::cstore::EncodedMetadata; use middle::free_region::FreeRegionMap; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; +use middle::exported_symbols::ExportedSymbols; use middle::stability; use mir::Mir; use mir::transform::Passes; @@ -64,6 +65,7 @@ use std::mem; use std::ops::Deref; use std::iter; use std::rc::Rc; +use std::sync::Arc; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; @@ -1218,6 +1220,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn crate_data_as_rc_any(self, cnum: CrateNum) -> Rc { self.cstore.crate_data_as_rc_any(cnum) } + + pub fn exported_symbols(self) -> Arc { + self.exported_symbol_set(LOCAL_CRATE) + } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 18c59d405a201..2d3dc6cd65bf8 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -23,6 +23,7 @@ use middle::region; use middle::resolve_lifetime::{Region, ObjectLifetimeDefault}; use middle::stability::{self, DeprecationEntry}; use middle::lang_items::{LanguageItems, LangItem}; +use middle::exported_symbols::ExportedSymbols; use mir; use mir::transform::{MirSuite, MirPassIndex}; use session::CompileResult; @@ -48,6 +49,7 @@ use std::mem; use std::collections::BTreeMap; use std::ops::Deref; use std::rc::Rc; +use std::sync::Arc; use syntax_pos::{Span, DUMMY_SP}; use syntax::attr; use syntax::ast; @@ -595,7 +597,7 @@ impl<'tcx> QueryDescription for queries::is_sanitizer_runtime<'tcx> { } } -impl<'tcx> QueryDescription for queries::exported_symbols<'tcx> { +impl<'tcx> QueryDescription for queries::exported_symbol_ids<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { format!("looking up the exported symbols of a crate") } @@ -745,6 +747,12 @@ impl<'tcx> QueryDescription for queries::all_crate_nums<'tcx> { } } +impl<'tcx> QueryDescription for queries::exported_symbol_set<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("exported symbol set") + } +} + // If enabled, send a message to the profile-queries thread macro_rules! profq_msg { ($tcx:expr, $msg:expr) => { @@ -1322,7 +1330,7 @@ define_maps! { <'tcx> [] fn lint_levels: lint_levels_node(CrateNum) -> Rc, [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, - [] fn exported_symbols: ExportedSymbols(CrateNum) -> Rc>, + [] fn exported_symbol_ids: ExportedSymbolIds(CrateNum) -> Rc>, [] fn native_libraries: NativeLibraries(CrateNum) -> Rc>, [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option, [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option, @@ -1371,6 +1379,9 @@ define_maps! { <'tcx> [] fn stability_index: stability_index_node(CrateNum) -> Rc>, [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Rc>, + + [] fn exported_symbol_set: exported_symbol_set_node(CrateNum) + -> Arc, } fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { @@ -1484,3 +1495,7 @@ fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::AllCrateNums } + +fn exported_symbol_set_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::ExportedSymbols +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b01179c43111b..9f7cb06488dde 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -956,7 +956,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, mir::provide(&mut local_providers); reachable::provide(&mut local_providers); rustc_privacy::provide(&mut local_providers); - trans::provide(&mut local_providers); + trans::provide_local(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); traits::provide(&mut local_providers); @@ -968,7 +968,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); - trans::provide(&mut extern_providers); + trans::provide_extern(&mut extern_providers); ty::provide_extern(&mut extern_providers); traits::provide_extern(&mut extern_providers); // FIXME(eddyb) get rid of this once we replace const_eval with miri. diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 74e4ffcdfffdc..3a116160bcab2 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -175,7 +175,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, extern_crate => { Rc::new(cdata.extern_crate.get()) } is_no_builtins => { cdata.is_no_builtins() } impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } - exported_symbols => { Rc::new(cdata.get_exported_symbols()) } + exported_symbol_ids => { Rc::new(cdata.get_exported_symbols()) } native_libraries => { Rc::new(cdata.get_native_libraries()) } plugin_registrar_fn => { cdata.root.plugin_registrar_fn.map(|index| { diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 487d9e059458c..ec436bcb241b0 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -19,8 +19,8 @@ use context::SharedCrateContext; use back::archive; use back::command::Command; -use back::symbol_export::ExportedSymbols; use rustc::middle::dependency_format::Linkage; +use rustc::middle::exported_symbols::ExportedSymbols; use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; use rustc_back::LinkerFlavor; use rustc::session::Session; diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 3e2d9f5c32e85..125b07a9505b1 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -16,6 +16,7 @@ use errors::{FatalError, Handler}; use llvm; use llvm::archive_ro::ArchiveRO; use llvm::{ModuleRef, TargetMachineRef, True, False}; +use rustc::middle::exported_symbols; use rustc::util::common::time; use rustc::util::common::path2cstr; use rustc::hir::def_id::LOCAL_CRATE; @@ -68,7 +69,7 @@ pub fn run(cgcx: &CodegenContext, symbol_export::crates_export_threshold(&cgcx.crate_types); let symbol_filter = &|&(ref name, _, level): &(String, _, _)| { - if symbol_export::is_below_threshold(level, export_threshold) { + if exported_symbols::is_below_threshold(level, export_threshold) { let mut bytes = Vec::with_capacity(name.len() + 1); bytes.extend(name.bytes()); Some(CString::new(bytes).unwrap()) diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index b546059b4c51d..b47d6f8ac2d70 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -8,199 +8,143 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use base; use monomorphize::Instance; use rustc::util::nodemap::{FxHashMap, NodeSet}; -use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX}; +use rustc::hir::def_id::{DefId, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX}; use rustc::session::config; use rustc::ty::TyCtxt; use rustc_allocator::ALLOCATOR_METHODS; +use rustc::middle::exported_symbols::{ExportedSymbols, SymbolExportLevel}; +use rustc::middle::exported_symbols::is_below_threshold; use syntax::attr; -/// The SymbolExportLevel of a symbols specifies from which kinds of crates -/// the symbol will be exported. `C` symbols will be exported from any -/// kind of crate, including cdylibs which export very few things. -/// `Rust` will only be exported if the crate produced is a Rust -/// dylib. -#[derive(Eq, PartialEq, Debug, Copy, Clone)] -pub enum SymbolExportLevel { - C, - Rust, -} - -/// The set of symbols exported from each crate in the crate graph. -#[derive(Debug)] -pub struct ExportedSymbols { - pub export_threshold: SymbolExportLevel, - exports: FxHashMap>, - local_exports: NodeSet, -} - -impl ExportedSymbols { - pub fn empty() -> ExportedSymbols { - ExportedSymbols { - export_threshold: SymbolExportLevel::C, - exports: FxHashMap(), - local_exports: NodeSet(), - } - } - - pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - local_exported_symbols: &NodeSet) - -> ExportedSymbols { - let export_threshold = crates_export_threshold(&tcx.sess.crate_types.borrow()); - - let mut local_crate: Vec<_> = local_exported_symbols - .iter() - .map(|&node_id| { - tcx.hir.local_def_id(node_id) - }) - .map(|def_id| { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)); - let export_level = export_level(tcx, def_id); - debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level); - (str::to_owned(&name), def_id, export_level) - }) - .collect(); - - let mut local_exports = local_crate - .iter() - .filter_map(|&(_, def_id, level)| { - if is_below_threshold(level, export_threshold) { - tcx.hir.as_local_node_id(def_id) - } else { - None - } - }) - .collect::(); - - const INVALID_DEF_ID: DefId = DefId { - krate: INVALID_CRATE, - index: CRATE_DEF_INDEX, - }; - - if let Some(_) = *tcx.sess.entry_fn.borrow() { - local_crate.push(("main".to_string(), - INVALID_DEF_ID, - SymbolExportLevel::C)); - } - - if tcx.sess.allocator_kind.get().is_some() { - for method in ALLOCATOR_METHODS { - local_crate.push((format!("__rust_{}", method.name), - INVALID_DEF_ID, - SymbolExportLevel::Rust)); +pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ExportedSymbols { + let export_threshold = crates_export_threshold(&tcx.sess.crate_types.borrow()); + let local_exported_symbols = base::find_exported_symbols(tcx); + + let mut local_crate: Vec<_> = local_exported_symbols + .iter() + .map(|&node_id| { + tcx.hir.local_def_id(node_id) + }) + .map(|def_id| { + let name = tcx.symbol_name(Instance::mono(tcx, def_id)); + let export_level = export_level(tcx, def_id); + debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level); + (str::to_owned(&name), def_id, export_level) + }) + .collect(); + + let mut local_exports = local_crate + .iter() + .filter_map(|&(_, def_id, level)| { + if is_below_threshold(level, export_threshold) { + tcx.hir.as_local_node_id(def_id) + } else { + None } - } - - if let Some(id) = tcx.sess.derive_registrar_fn.get() { - let def_id = tcx.hir.local_def_id(id); - let idx = def_id.index; - let disambiguator = tcx.sess.local_crate_disambiguator(); - let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx); - local_crate.push((registrar, def_id, SymbolExportLevel::C)); - local_exports.insert(id); - } + }) + .collect::(); + + const INVALID_DEF_ID: DefId = DefId { + krate: INVALID_CRATE, + index: CRATE_DEF_INDEX, + }; + + if let Some(_) = *tcx.sess.entry_fn.borrow() { + local_crate.push(("main".to_string(), + INVALID_DEF_ID, + SymbolExportLevel::C)); + } - if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) { - local_crate.push((metadata_symbol_name(tcx), + if tcx.sess.allocator_kind.get().is_some() { + for method in ALLOCATOR_METHODS { + local_crate.push((format!("__rust_{}", method.name), INVALID_DEF_ID, SymbolExportLevel::Rust)); } + } - let mut exports = FxHashMap(); - exports.insert(LOCAL_CRATE, local_crate); + if let Some(id) = tcx.sess.derive_registrar_fn.get() { + let def_id = tcx.hir.local_def_id(id); + let idx = def_id.index; + let disambiguator = tcx.sess.local_crate_disambiguator(); + let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx); + local_crate.push((registrar, def_id, SymbolExportLevel::C)); + local_exports.insert(id); + } - for &cnum in tcx.crates().iter() { - debug_assert!(cnum != LOCAL_CRATE); + if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) { + local_crate.push((metadata_symbol_name(tcx), + INVALID_DEF_ID, + SymbolExportLevel::Rust)); + } - // If this crate is a plugin and/or a custom derive crate, then - // we're not even going to link those in so we skip those crates. - if tcx.plugin_registrar_fn(cnum).is_some() || - tcx.derive_registrar_fn(cnum).is_some() { - continue; - } + let mut exports = FxHashMap(); + exports.insert(LOCAL_CRATE, local_crate); - // Check to see if this crate is a "special runtime crate". These - // crates, implementation details of the standard library, typically - // have a bunch of `pub extern` and `#[no_mangle]` functions as the - // ABI between them. We don't want their symbols to have a `C` - // export level, however, as they're just implementation details. - // Down below we'll hardwire all of the symbols to the `Rust` export - // level instead. - let special_runtime_crate = - tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum); - - let crate_exports = tcx - .exported_symbols(cnum) - .iter() - .map(|&def_id| { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)); - let export_level = if special_runtime_crate { - // We can probably do better here by just ensuring that - // it has hidden visibility rather than public - // visibility, as this is primarily here to ensure it's - // not stripped during LTO. - // - // In general though we won't link right if these - // symbols are stripped, and LTO currently strips them. - if &*name == "rust_eh_personality" || - &*name == "rust_eh_register_frames" || - &*name == "rust_eh_unregister_frames" { - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust - } - } else { - export_level(tcx, def_id) - }; - debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level); - (str::to_owned(&name), def_id, export_level) - }) - .collect(); - - exports.insert(cnum, crate_exports); - } + for &cnum in tcx.crates().iter() { + debug_assert!(cnum != LOCAL_CRATE); - return ExportedSymbols { - export_threshold, - exports, - local_exports, - }; - - fn export_level(tcx: TyCtxt, - sym_def_id: DefId) - -> SymbolExportLevel { - let attrs = tcx.get_attrs(sym_def_id); - if attr::contains_extern_indicator(tcx.sess.diagnostic(), &attrs) { - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust - } + // If this crate is a plugin and/or a custom derive crate, then + // we're not even going to link those in so we skip those crates. + if tcx.plugin_registrar_fn(cnum).is_some() || + tcx.derive_registrar_fn(cnum).is_some() { + continue; } - } - pub fn local_exports(&self) -> &NodeSet { - &self.local_exports - } + // Check to see if this crate is a "special runtime crate". These + // crates, implementation details of the standard library, typically + // have a bunch of `pub extern` and `#[no_mangle]` functions as the + // ABI between them. We don't want their symbols to have a `C` + // export level, however, as they're just implementation details. + // Down below we'll hardwire all of the symbols to the `Rust` export + // level instead. + let special_runtime_crate = + tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum); + + let crate_exports = tcx + .exported_symbol_ids(cnum) + .iter() + .map(|&def_id| { + let name = tcx.symbol_name(Instance::mono(tcx, def_id)); + let export_level = if special_runtime_crate { + // We can probably do better here by just ensuring that + // it has hidden visibility rather than public + // visibility, as this is primarily here to ensure it's + // not stripped during LTO. + // + // In general though we won't link right if these + // symbols are stripped, and LTO currently strips them. + if &*name == "rust_eh_personality" || + &*name == "rust_eh_register_frames" || + &*name == "rust_eh_unregister_frames" { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust + } + } else { + export_level(tcx, def_id) + }; + debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level); + (str::to_owned(&name), def_id, export_level) + }) + .collect(); - pub fn exported_symbols(&self, - cnum: CrateNum) - -> &[(String, DefId, SymbolExportLevel)] { - match self.exports.get(&cnum) { - Some(exports) => exports, - None => &[] - } + exports.insert(cnum, crate_exports); } - pub fn for_each_exported_symbol(&self, - cnum: CrateNum, - mut f: F) - where F: FnMut(&str, DefId, SymbolExportLevel) - { - for &(ref name, def_id, export_level) in self.exported_symbols(cnum) { - if is_below_threshold(export_level, self.export_threshold) { - f(&name, def_id, export_level) - } + return ExportedSymbols::new(export_threshold, exports, local_exports); + + fn export_level(tcx: TyCtxt, + sym_def_id: DefId) + -> SymbolExportLevel { + let attrs = tcx.get_attrs(sym_def_id); + if attr::contains_extern_indicator(tcx.sess.diagnostic(), &attrs) { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust } } } @@ -233,14 +177,3 @@ pub fn crates_export_threshold(crate_types: &[config::CrateType]) SymbolExportLevel::C } } - -pub fn is_below_threshold(level: SymbolExportLevel, - threshold: SymbolExportLevel) - -> bool { - if threshold == SymbolExportLevel::Rust { - // We export everything from Rust dylibs - true - } else { - level == SymbolExportLevel::C - } -} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 68140011e7ec3..d241edca0ead7 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -11,7 +11,7 @@ use back::lto; use back::link::{self, get_linker, remove}; use back::linker::LinkerInfo; -use back::symbol_export::ExportedSymbols; +use rustc::middle::exported_symbols::ExportedSymbols; use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; use rustc::dep_graph::DepGraph; use rustc::middle::cstore::{LinkMeta, EncodedMetadata}; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 1ea38eadb759c..5f8e95b6ca98f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -31,7 +31,7 @@ use super::ModuleKind; use assert_module_sources; use back::link; use back::linker::LinkerInfo; -use back::symbol_export::{self, ExportedSymbols}; +use back::symbol_export; use back::write::{self, OngoingCrateTranslation}; use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param}; use llvm; @@ -42,6 +42,7 @@ use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::dep_graph::AssertDepGraphSafe; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; +use rustc::middle::exported_symbols::{ExportedSymbols, SymbolExportLevel}; use rustc::hir::map as hir_map; use rustc::util::common::{time, print_time_passes_entry}; use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType}; @@ -973,7 +974,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.debugging_opts.no_trans || !tcx.sess.opts.output_types.should_trans() { - let empty_exported_symbols = ExportedSymbols::empty(); + let empty_exported_symbols = ExportedSymbols::new( + SymbolExportLevel::C, + Default::default(), + Default::default(), + ); let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols); let ongoing_translation = write::start_async_translation( tcx.sess, @@ -1001,13 +1006,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return ongoing_translation; } - let exported_symbols = Arc::new(ExportedSymbols::compute(tcx, - &exported_symbol_node_ids)); + let exported_symbols = tcx.exported_symbols(); // Run the translation item collector and partition the collected items into // codegen units. let (translation_items, codegen_units) = - collect_and_partition_translation_items(&shared_ccx, &exported_symbols); + collect_and_partition_translation_items(shared_ccx.tcx(), &exported_symbols); assert!(codegen_units.len() <= 1 || !tcx.sess.lto()); @@ -1394,13 +1398,13 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_i } } -fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, exported_symbols: &ExportedSymbols) -> (FxHashSet>, Vec>) { - let time_passes = scx.sess().time_passes(); + let time_passes = tcx.sess.time_passes(); - let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items { + let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items { Some(ref s) => { let mode_string = s.to_lowercase(); let mode_string = mode_string.trim(); @@ -1411,7 +1415,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a let message = format!("Unknown codegen-item collection mode '{}'. \ Falling back to 'lazy' mode.", mode_string); - scx.sess().warn(&message); + tcx.sess.warn(&message); } TransItemCollectionMode::Lazy @@ -1422,33 +1426,33 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a let (items, inlining_map) = time(time_passes, "translation item collection", || { - collector::collect_crate_translation_items(scx.tcx(), + collector::collect_crate_translation_items(tcx, exported_symbols, collection_mode) }); - assert_symbols_are_distinct(scx.tcx(), items.iter()); + assert_symbols_are_distinct(tcx, items.iter()); - let strategy = if scx.sess().opts.debugging_opts.incremental.is_some() { + let strategy = if tcx.sess.opts.debugging_opts.incremental.is_some() { PartitioningStrategy::PerModule } else { - PartitioningStrategy::FixedUnitCount(scx.sess().opts.cg.codegen_units) + PartitioningStrategy::FixedUnitCount(tcx.sess.opts.cg.codegen_units) }; let codegen_units = time(time_passes, "codegen unit partitioning", || { - partitioning::partition(scx.tcx(), + partitioning::partition(tcx, items.iter().cloned(), strategy, &inlining_map, exported_symbols) }); - assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() || - scx.tcx().sess.opts.debugging_opts.incremental.is_some()); + assert!(tcx.sess.opts.cg.codegen_units == codegen_units.len() || + tcx.sess.opts.debugging_opts.incremental.is_some()); let translation_items: FxHashSet> = items.iter().cloned().collect(); - if scx.sess().opts.debugging_opts.print_trans_items.is_some() { + if tcx.sess.opts.debugging_opts.print_trans_items.is_some() { let mut item_to_cgus = FxHashMap(); for cgu in &codegen_units { @@ -1462,7 +1466,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a let mut item_keys: Vec<_> = items .iter() .map(|i| { - let mut output = i.to_string(scx.tcx()); + let mut output = i.to_string(tcx); output.push_str(" @@"); let mut empty = Vec::new(); let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index bda035fc343c8..ff550d10c6d75 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -194,6 +194,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; +use rustc::middle::exported_symbols::ExportedSymbols; use rustc::middle::lang_items::{ExchangeMallocFnLangItem}; use rustc::traits; use rustc::ty::subst::Substs; @@ -209,7 +210,6 @@ use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; use trans_item::{TransItem, DefPathBasedNames, InstantiationMode}; use rustc_data_structures::bitvec::BitVector; -use back::symbol_export::ExportedSymbols; #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum TransItemCollectionMode { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 3ad96d482f116..94695b4e0463c 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -14,10 +14,10 @@ use llvm::{ContextRef, ModuleRef, ValueRef}; use rustc::dep_graph::{DepGraph, DepGraphSafe}; use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::middle::exported_symbols::ExportedSymbols; use rustc::traits; use debuginfo; use callee; -use back::symbol_export::ExportedSymbols; use base; use declare; use monomorphize::Instance; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 256200a6e9572..8c8bd6a5e509a 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -64,16 +64,17 @@ extern crate serialize; extern crate gcc; // Used to locate MSVC, not gcc :) pub use base::trans_crate; -pub use back::symbol_names::provide; pub use metadata::LlvmMetadataLoader; pub use llvm_util::{init, target_features, print_version, print_passes, print, enable_llvm_debug}; use std::rc::Rc; +use std::sync::Arc; -use rustc::hir::def_id::CrateNum; -use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource}; +use rustc::ty::maps::Providers; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; pub mod back { mod archive; @@ -247,3 +248,15 @@ pub struct CrateInfo { } __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } + +pub fn provide_local(providers: &mut Providers) { + back::symbol_names::provide(providers); + providers.exported_symbol_set = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Arc::new(back::symbol_export::compute(tcx)) + }; +} + +pub fn provide_extern(providers: &mut Providers) { + back::symbol_names::provide(providers); +} diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index d436d0d8b6a27..d47739b906cdc 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -102,7 +102,6 @@ //! source-level module, functions from the same module will be available for //! inlining, even when they are not marked #[inline]. -use back::symbol_export::ExportedSymbols; use collector::InliningMap; use common; use context::SharedCrateContext; @@ -110,6 +109,7 @@ use llvm; use rustc::dep_graph::{DepNode, WorkProductId}; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; +use rustc::middle::exported_symbols::ExportedSymbols; use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER; use rustc::ty::{self, TyCtxt, InstanceDef}; use rustc::ty::item_path::characteristic_def_id_of_type; From 132bde7cf1ee102b6eb370561bf9af9cfbfb4224 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Sep 2017 11:04:46 -0700 Subject: [PATCH 05/11] rustc: Make trans collect/partition a query This commit moves the `collect_and_partition_translation_items` function into a query on `TyCtxt` instead of a free function in trans, allowing us to track dependencies and such of the function. --- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/lib.rs | 1 + src/librustc/middle/trans.rs | 69 +++++++++ src/librustc/ty/maps.rs | 14 ++ src/librustc_trans/back/linker.rs | 6 +- src/librustc_trans/base.rs | 134 +++++++++++------- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/consts.rs | 6 +- src/librustc_trans/context.rs | 8 +- src/librustc_trans/lib.rs | 1 + src/librustc_trans/partitioning.rs | 143 +++++++++---------- src/librustc_trans/trans_item.rs | 215 +++++++++++++++-------------- 12 files changed, 352 insertions(+), 248 deletions(-) create mode 100644 src/librustc/middle/trans.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 757a256164e08..afd31306817c0 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -576,6 +576,7 @@ define_dep_nodes!( <'tcx> [] StabilityIndex, [] AllCrateNums, [] ExportedSymbols, + [] CollectAndPartitionTranslationItems, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 59edc9fb083ac..f7b1d2d92f717 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -104,6 +104,7 @@ pub mod middle { pub mod recursion_limit; pub mod resolve_lifetime; pub mod stability; + pub mod trans; pub mod weak_lang_items; } diff --git a/src/librustc/middle/trans.rs b/src/librustc/middle/trans.rs new file mode 100644 index 0000000000000..e871a38c4eff0 --- /dev/null +++ b/src/librustc/middle/trans.rs @@ -0,0 +1,69 @@ +use syntax::ast::NodeId; +use syntax::symbol::InternedString; +use ty::Instance; +use util::nodemap::FxHashMap; + +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub enum TransItem<'tcx> { + Fn(Instance<'tcx>), + Static(NodeId), + GlobalAsm(NodeId), +} + +pub struct CodegenUnit<'tcx> { + /// A name for this CGU. Incremental compilation requires that + /// name be unique amongst **all** crates. Therefore, it should + /// contain something unique to this crate (e.g., a module path) + /// as well as the crate name and disambiguator. + name: InternedString, + items: FxHashMap, (Linkage, Visibility)>, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum Linkage { + External, + AvailableExternally, + LinkOnceAny, + LinkOnceODR, + WeakAny, + WeakODR, + Appending, + Internal, + Private, + ExternalWeak, + Common, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum Visibility { + Default, + Hidden, + Protected, +} + +impl<'tcx> CodegenUnit<'tcx> { + pub fn new(name: InternedString) -> CodegenUnit<'tcx> { + CodegenUnit { + name: name, + items: FxHashMap(), + } + } + + pub fn name(&self) -> &InternedString { + &self.name + } + + pub fn set_name(&mut self, name: InternedString) { + self.name = name; + } + + pub fn items(&self) -> &FxHashMap, (Linkage, Visibility)> { + &self.items + } + + pub fn items_mut(&mut self) + -> &mut FxHashMap, (Linkage, Visibility)> + { + &mut self.items + } +} diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 2d3dc6cd65bf8..c6fff0071bfcb 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -24,6 +24,7 @@ use middle::resolve_lifetime::{Region, ObjectLifetimeDefault}; use middle::stability::{self, DeprecationEntry}; use middle::lang_items::{LanguageItems, LangItem}; use middle::exported_symbols::ExportedSymbols; +use middle::trans::{TransItem, CodegenUnit}; use mir; use mir::transform::{MirSuite, MirPassIndex}; use session::CompileResult; @@ -753,6 +754,12 @@ impl<'tcx> QueryDescription for queries::exported_symbol_set<'tcx> { } } +impl<'tcx> QueryDescription for queries::collect_and_partition_translation_items<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("collect_and_partition_translation_items") + } +} + // If enabled, send a message to the profile-queries thread macro_rules! profq_msg { ($tcx:expr, $msg:expr) => { @@ -1382,6 +1389,9 @@ define_maps! { <'tcx> [] fn exported_symbol_set: exported_symbol_set_node(CrateNum) -> Arc, + [] fn collect_and_partition_translation_items: + collect_and_partition_translation_items_node(CrateNum) + -> (Arc>>, Vec>>), } fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { @@ -1499,3 +1509,7 @@ fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { fn exported_symbol_set_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::ExportedSymbols } + +fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::CollectAndPartitionTranslationItems +} diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index ec436bcb241b0..1eb3e86a15b81 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -34,11 +34,11 @@ pub struct LinkerInfo { } impl<'a, 'tcx> LinkerInfo { - pub fn new(scx: &SharedCrateContext<'a, 'tcx>, - exports: &ExportedSymbols) -> LinkerInfo { + pub fn new(scx: &SharedCrateContext<'a, 'tcx>) -> LinkerInfo { + let exports = scx.tcx().exported_symbols(); LinkerInfo { exports: scx.sess().crate_types.borrow().iter().map(|&c| { - (c, exported_symbols(scx, exports, c)) + (c, exported_symbols(scx, &exports, c)) }).collect(), } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 5f8e95b6ca98f..7d0e7c210746b 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -33,16 +33,18 @@ use back::link; use back::linker::LinkerInfo; use back::symbol_export; use back::write::{self, OngoingCrateTranslation}; -use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param}; +use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; use llvm; use metadata; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::middle::lang_items::StartFnLangItem; +use rustc::middle::trans::{Linkage, Visibility}; use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes}; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::Providers; use rustc::dep_graph::AssertDepGraphSafe; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; -use rustc::middle::exported_symbols::{ExportedSymbols, SymbolExportLevel}; +use rustc::middle::exported_symbols::ExportedSymbols; use rustc::hir::map as hir_map; use rustc::util::common::{time, print_time_passes_entry}; use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType}; @@ -68,10 +70,10 @@ use machine; use meth; use mir; use monomorphize::{self, Instance}; -use partitioning::{self, PartitioningStrategy, CodegenUnit}; +use partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt}; use symbol_names_test; use time_graph; -use trans_item::{TransItem, DefPathBasedNames}; +use trans_item::{TransItem, TransItemExt, DefPathBasedNames}; use type_::Type; use type_of; use value::Value; @@ -615,7 +617,9 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance mir::trans_mir(ccx, lldecl, &mir, instance, sig); } -pub fn llvm_linkage_by_name(name: &str) -> Option { +pub fn linkage_by_name(name: &str) -> Option { + use rustc::middle::trans::Linkage::*; + // Use the names from src/llvm/docs/LangRef.rst here. Most types are only // applicable to variable declarations and may not really make sense for // Rust code in the first place but whitelist them anyway and trust that @@ -625,17 +629,17 @@ pub fn llvm_linkage_by_name(name: &str) -> Option { // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported // and don't have to be, LLVM treats them as no-ops. match name { - "appending" => Some(llvm::Linkage::AppendingLinkage), - "available_externally" => Some(llvm::Linkage::AvailableExternallyLinkage), - "common" => Some(llvm::Linkage::CommonLinkage), - "extern_weak" => Some(llvm::Linkage::ExternalWeakLinkage), - "external" => Some(llvm::Linkage::ExternalLinkage), - "internal" => Some(llvm::Linkage::InternalLinkage), - "linkonce" => Some(llvm::Linkage::LinkOnceAnyLinkage), - "linkonce_odr" => Some(llvm::Linkage::LinkOnceODRLinkage), - "private" => Some(llvm::Linkage::PrivateLinkage), - "weak" => Some(llvm::Linkage::WeakAnyLinkage), - "weak_odr" => Some(llvm::Linkage::WeakODRLinkage), + "appending" => Some(Appending), + "available_externally" => Some(AvailableExternally), + "common" => Some(Common), + "extern_weak" => Some(ExternalWeak), + "external" => Some(External), + "internal" => Some(Internal), + "linkonce" => Some(LinkOnceAny), + "linkonce_odr" => Some(LinkOnceODR), + "private" => Some(Private), + "weak" => Some(WeakAny), + "weak_odr" => Some(WeakODR), _ => None, } } @@ -974,12 +978,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.debugging_opts.no_trans || !tcx.sess.opts.output_types.should_trans() { - let empty_exported_symbols = ExportedSymbols::new( - SymbolExportLevel::C, - Default::default(), - Default::default(), - ); - let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols); + let linker_info = LinkerInfo::new(&shared_ccx); let ongoing_translation = write::start_async_translation( tcx.sess, output_filenames, @@ -987,7 +986,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.crate_name(LOCAL_CRATE), link_meta, metadata, - Arc::new(empty_exported_symbols), + shared_ccx.tcx().exported_symbols(), no_builtins, None, linker_info, @@ -1006,16 +1005,14 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return ongoing_translation; } - let exported_symbols = tcx.exported_symbols(); - // Run the translation item collector and partition the collected items into // codegen units. let (translation_items, codegen_units) = - collect_and_partition_translation_items(shared_ccx.tcx(), &exported_symbols); + shared_ccx.tcx().collect_and_partition_translation_items(LOCAL_CRATE); assert!(codegen_units.len() <= 1 || !tcx.sess.lto()); - let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols); + let linker_info = LinkerInfo::new(&shared_ccx); let subsystem = attr::first_attr_value_str_by_name(&krate.attrs, "windows_subsystem"); let windows_subsystem = subsystem.map(|subsystem| { @@ -1039,7 +1036,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.crate_name(LOCAL_CRATE), link_meta, metadata, - exported_symbols.clone(), + tcx.exported_symbols(), no_builtins, windows_subsystem, linker_info, @@ -1090,8 +1087,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata_module, codegen_unit_count == 0); - let translation_items = Arc::new(translation_items); - let mut all_stats = Stats::default(); let mut module_dispositions = tcx.sess.opts.incremental.as_ref().map(|_| Vec::new()); @@ -1124,7 +1119,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, AssertDepGraphSafe(&shared_ccx), AssertDepGraphSafe((cgu, translation_items.clone(), - exported_symbols.clone())), + tcx.exported_symbols())), module_translation); all_stats.extend(stats); @@ -1165,7 +1160,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn module_translation<'a, 'tcx>( scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, - args: AssertDepGraphSafe<(CodegenUnit<'tcx>, + args: AssertDepGraphSafe<(Arc>, Arc>>, Arc)>) -> (Stats, ModuleTranslation) @@ -1174,7 +1169,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let AssertDepGraphSafe(scx) = scx; let AssertDepGraphSafe((cgu, crate_trans_items, exported_symbols)) = args; - let cgu_name = String::from(cgu.name()); + let cgu_name = cgu.name().to_string(); let cgu_id = cgu.work_product_id(); let symbol_name_hash = cgu.compute_symbol_name_hash(scx); @@ -1398,11 +1393,14 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_i } } -fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - exported_symbols: &ExportedSymbols) - -> (FxHashSet>, - Vec>) { +fn collect_and_partition_translation_items<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum, +) -> (Arc>>, Vec>>) +{ + assert_eq!(cnum, LOCAL_CRATE); let time_passes = tcx.sess.time_passes(); + let exported_symbols = tcx.exported_symbols(); let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items { Some(ref s) => { @@ -1427,7 +1425,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> let (items, inlining_map) = time(time_passes, "translation item collection", || { collector::collect_crate_translation_items(tcx, - exported_symbols, + &exported_symbols, collection_mode) }); @@ -1444,7 +1442,10 @@ fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> items.iter().cloned(), strategy, &inlining_map, - exported_symbols) + &exported_symbols) + .into_iter() + .map(Arc::new) + .collect::>() }); assert!(tcx.sess.opts.cg.codegen_units == codegen_units.len() || @@ -1477,17 +1478,17 @@ fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> output.push_str(&cgu_name); let linkage_abbrev = match linkage { - llvm::Linkage::ExternalLinkage => "External", - llvm::Linkage::AvailableExternallyLinkage => "Available", - llvm::Linkage::LinkOnceAnyLinkage => "OnceAny", - llvm::Linkage::LinkOnceODRLinkage => "OnceODR", - llvm::Linkage::WeakAnyLinkage => "WeakAny", - llvm::Linkage::WeakODRLinkage => "WeakODR", - llvm::Linkage::AppendingLinkage => "Appending", - llvm::Linkage::InternalLinkage => "Internal", - llvm::Linkage::PrivateLinkage => "Private", - llvm::Linkage::ExternalWeakLinkage => "ExternalWeak", - llvm::Linkage::CommonLinkage => "Common", + Linkage::External => "External", + Linkage::AvailableExternally => "Available", + Linkage::LinkOnceAny => "OnceAny", + Linkage::LinkOnceODR => "OnceODR", + Linkage::WeakAny => "WeakAny", + Linkage::WeakODR => "WeakODR", + Linkage::Appending => "Appending", + Linkage::Internal => "Internal", + Linkage::Private => "Private", + Linkage::ExternalWeak => "ExternalWeak", + Linkage::Common => "Common", }; output.push_str("["); @@ -1505,7 +1506,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx> } } - (translation_items, codegen_units) + (Arc::new(translation_items), codegen_units) } impl CrateInfo { @@ -1550,3 +1551,32 @@ impl CrateInfo { return info } } + +pub fn provide(providers: &mut Providers) { + providers.collect_and_partition_translation_items = + collect_and_partition_translation_items; +} + +pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage { + match linkage { + Linkage::External => llvm::Linkage::ExternalLinkage, + Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage, + Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage, + Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage, + Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage, + Linkage::WeakODR => llvm::Linkage::WeakODRLinkage, + Linkage::Appending => llvm::Linkage::AppendingLinkage, + Linkage::Internal => llvm::Linkage::InternalLinkage, + Linkage::Private => llvm::Linkage::PrivateLinkage, + Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage, + Linkage::Common => llvm::Linkage::CommonLinkage, + } +} + +pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility { + match linkage { + Visibility::Default => llvm::Visibility::Default, + Visibility::Hidden => llvm::Visibility::Hidden, + Visibility::Protected => llvm::Visibility::Protected, + } +} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index ff550d10c6d75..a45bcb51ab594 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -207,7 +207,7 @@ use common::{def_ty, instance_ty, type_is_sized}; use monomorphize::{self, Instance}; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; -use trans_item::{TransItem, DefPathBasedNames, InstantiationMode}; +use trans_item::{TransItem, TransItemExt, DefPathBasedNames, InstantiationMode}; use rustc_data_structures::bitvec::BitVector; diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index a566cddde566b..4f78e77fc690c 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -16,7 +16,7 @@ use rustc::hir::map as hir_map; use rustc::middle::const_val::ConstEvalErr; use {debuginfo, machine}; use base; -use trans_item::TransItem; +use trans_item::{TransItem, TransItemExt}; use common::{self, CrateContext, val_ty}; use declare; use monomorphize::Instance; @@ -150,7 +150,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { // extern "C" fn() from being non-null, so we can't just declare a // static and call it a day. Some linkages (like weak) will make it such // that the static actually has a null value. - let linkage = match base::llvm_linkage_by_name(&name.as_str()) { + let linkage = match base::linkage_by_name(&name.as_str()) { Some(linkage) => linkage, None => { ccx.sess().span_fatal(span, "invalid linkage specified"); @@ -165,7 +165,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { unsafe { // Declare a symbol `foo` with the desired linkage. let g1 = declare::declare_global(ccx, &sym, llty2); - llvm::LLVMRustSetLinkage(g1, linkage); + llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 94695b4e0463c..7a2db29705d83 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -93,7 +93,7 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> { llmod: ModuleRef, llcx: ContextRef, stats: Stats, - codegen_unit: CodegenUnit<'tcx>, + codegen_unit: Arc>, /// The translation items of the whole crate. crate_trans_items: Arc>>, @@ -330,7 +330,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { common::type_is_freeze(self.tcx, ty) } - pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { + pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx } @@ -353,7 +353,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { pub fn new(shared: &SharedCrateContext<'a, 'tcx>, - codegen_unit: CodegenUnit<'tcx>, + codegen_unit: Arc>, crate_trans_items: Arc>>, exported_symbols: Arc,) -> LocalCrateContext<'a, 'tcx> { @@ -465,7 +465,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local_ccx } - pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { + pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { self.shared.tcx } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 8c8bd6a5e509a..701c7be8ad6d9 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -251,6 +251,7 @@ __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } pub fn provide_local(providers: &mut Providers) { back::symbol_names::provide(providers); + base::provide(providers); providers.exported_symbol_set = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); Arc::new(back::symbol_export::compute(tcx)) diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index d47739b906cdc..d4aecb9e56caa 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -105,11 +105,11 @@ use collector::InliningMap; use common; use context::SharedCrateContext; -use llvm; use rustc::dep_graph::{DepNode, WorkProductId}; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; use rustc::middle::exported_symbols::ExportedSymbols; +use rustc::middle::trans::{Linkage, Visibility}; use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER; use rustc::ty::{self, TyCtxt, InstanceDef}; use rustc::ty::item_path::characteristic_def_id_of_type; @@ -119,7 +119,9 @@ use std::collections::hash_map::Entry; use std::hash::Hash; use syntax::ast::NodeId; use syntax::symbol::{Symbol, InternedString}; -use trans_item::{TransItem, InstantiationMode}; +use trans_item::{TransItem, TransItemExt, InstantiationMode}; + +pub use rustc::middle::trans::CodegenUnit; pub enum PartitioningStrategy { /// Generate one codegen unit per source-level module. @@ -129,53 +131,34 @@ pub enum PartitioningStrategy { FixedUnitCount(usize) } -pub struct CodegenUnit<'tcx> { - /// A name for this CGU. Incremental compilation requires that - /// name be unique amongst **all** crates. Therefore, it should - /// contain something unique to this crate (e.g., a module path) - /// as well as the crate name and disambiguator. - name: InternedString, - - items: FxHashMap, (llvm::Linkage, llvm::Visibility)>, -} - -impl<'tcx> CodegenUnit<'tcx> { - pub fn new(name: InternedString, - items: FxHashMap, (llvm::Linkage, llvm::Visibility)>) - -> Self { - CodegenUnit { - name, - items, - } - } +pub trait CodegenUnitExt<'tcx> { + fn as_codegen_unit(&self) -> &CodegenUnit<'tcx>; - pub fn empty(name: InternedString) -> Self { - Self::new(name, FxHashMap()) + fn contains_item(&self, item: &TransItem<'tcx>) -> bool { + self.items().contains_key(item) } - pub fn contains_item(&self, item: &TransItem<'tcx>) -> bool { - self.items.contains_key(item) + fn name<'a>(&'a self) -> &'a InternedString + where 'tcx: 'a, + { + &self.as_codegen_unit().name() } - pub fn name(&self) -> &str { - &self.name + fn items(&self) -> &FxHashMap, (Linkage, Visibility)> { + &self.as_codegen_unit().items() } - pub fn items(&self) -> &FxHashMap, (llvm::Linkage, llvm::Visibility)> { - &self.items - } - - pub fn work_product_id(&self) -> WorkProductId { + fn work_product_id(&self) -> WorkProductId { WorkProductId::from_cgu_name(self.name()) } - pub fn work_product_dep_node(&self) -> DepNode { + fn work_product_dep_node(&self) -> DepNode { self.work_product_id().to_dep_node() } - pub fn compute_symbol_name_hash<'a>(&self, - scx: &SharedCrateContext<'a, 'tcx>) - -> u64 { + fn compute_symbol_name_hash<'a>(&self, + scx: &SharedCrateContext<'a, 'tcx>) + -> u64 { let mut state = IchHasher::new(); let all_items = self.items_in_deterministic_order(scx.tcx()); for (item, (linkage, visibility)) in all_items { @@ -188,10 +171,10 @@ impl<'tcx> CodegenUnit<'tcx> { state.finish().to_smaller_hash() } - pub fn items_in_deterministic_order<'a>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Vec<(TransItem<'tcx>, - (llvm::Linkage, llvm::Visibility))> { + fn items_in_deterministic_order<'a>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> Vec<(TransItem<'tcx>, + (Linkage, Visibility))> { // The codegen tests rely on items being process in the same order as // they appear in the file, so for local items, we sort by node_id first #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -209,7 +192,7 @@ impl<'tcx> CodegenUnit<'tcx> { }, item.symbol_name(tcx)) } - let items: Vec<_> = self.items.iter().map(|(&i, &l)| (i, l)).collect(); + let items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect(); let mut items : Vec<_> = items.iter() .map(|il| (il, item_sort_key(tcx, il.0))).collect(); items.sort_by(|&(_, ref key1), &(_, ref key2)| key1.cmp(key2)); @@ -217,6 +200,11 @@ impl<'tcx> CodegenUnit<'tcx> { } } +impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> { + fn as_codegen_unit(&self) -> &CodegenUnit<'tcx> { + self + } +} // Anything we can't find a proper codegen unit for goes into this. const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; @@ -267,7 +255,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } = post_inlining; result.sort_by(|cgu1, cgu2| { - (&cgu1.name[..]).cmp(&cgu2.name[..]) + cgu1.name().cmp(cgu2.name()) }); if tcx.sess.opts.enable_dep_node_debug_strs() { @@ -329,14 +317,14 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let make_codegen_unit = || { - CodegenUnit::empty(codegen_unit_name.clone()) + CodegenUnit::new(codegen_unit_name.clone()) }; let codegen_unit = codegen_units.entry(codegen_unit_name.clone()) .or_insert_with(make_codegen_unit); let (linkage, visibility) = match trans_item.explicit_linkage(tcx) { - Some(explicit_linkage) => (explicit_linkage, llvm::Visibility::Default), + Some(explicit_linkage) => (explicit_linkage, Visibility::Default), None => { match trans_item { TransItem::Fn(ref instance) => { @@ -344,14 +332,14 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, InstanceDef::Item(def_id) => { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { if exported_symbols.contains(&node_id) { - llvm::Visibility::Default + Visibility::Default } else { internalization_candidates.insert(trans_item); - llvm::Visibility::Hidden + Visibility::Hidden } } else { internalization_candidates.insert(trans_item); - llvm::Visibility::Hidden + Visibility::Hidden } } InstanceDef::FnPtrShim(..) | @@ -365,23 +353,23 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_item) } }; - (llvm::ExternalLinkage, visibility) + (Linkage::External, visibility) } TransItem::Static(node_id) | TransItem::GlobalAsm(node_id) => { let visibility = if exported_symbols.contains(&node_id) { - llvm::Visibility::Default + Visibility::Default } else { internalization_candidates.insert(trans_item); - llvm::Visibility::Hidden + Visibility::Hidden }; - (llvm::ExternalLinkage, visibility) + (Linkage::External, visibility) } } } }; - codegen_unit.items.insert(trans_item, (linkage, visibility)); + codegen_unit.items_mut().insert(trans_item, (linkage, visibility)); roots.insert(trans_item); } } @@ -391,7 +379,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if codegen_units.is_empty() { let codegen_unit_name = Symbol::intern(FALLBACK_CODEGEN_UNIT).as_str(); codegen_units.insert(codegen_unit_name.clone(), - CodegenUnit::empty(codegen_unit_name.clone())); + CodegenUnit::new(codegen_unit_name.clone())); } PreInliningPartitioning { @@ -414,17 +402,17 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< // translation items in a given unit. This could be improved on. while codegen_units.len() > target_cgu_count { // Sort small cgus to the back - codegen_units.sort_by_key(|cgu| -(cgu.items.len() as i64)); - let smallest = codegen_units.pop().unwrap(); + codegen_units.sort_by_key(|cgu| -(cgu.items().len() as i64)); + let mut smallest = codegen_units.pop().unwrap(); let second_smallest = codegen_units.last_mut().unwrap(); - for (k, v) in smallest.items.into_iter() { - second_smallest.items.insert(k, v); + for (k, v) in smallest.items_mut().drain() { + second_smallest.items_mut().insert(k, v); } } for (index, cgu) in codegen_units.iter_mut().enumerate() { - cgu.name = numbered_codegen_unit_name(crate_name, index); + cgu.set_name(numbered_codegen_unit_name(crate_name, index)); } // If the initial partitioning contained less than target_cgu_count to begin @@ -432,8 +420,8 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< // we reach the target count while codegen_units.len() < target_cgu_count { let index = codegen_units.len(); - codegen_units.push( - CodegenUnit::empty(numbered_codegen_unit_name(crate_name, index))); + let name = numbered_codegen_unit_name(crate_name, index); + codegen_units.push(CodegenUnit::new(name)); } } @@ -454,20 +442,17 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit for old_codegen_unit in initial_cgus { // Collect all items that need to be available in this codegen unit let mut reachable = FxHashSet(); - for root in old_codegen_unit.items.keys() { + for root in old_codegen_unit.items().keys() { follow_inlining(*root, inlining_map, &mut reachable); } - let mut new_codegen_unit = CodegenUnit { - name: old_codegen_unit.name, - items: FxHashMap(), - }; + let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name().clone()); // Add all translation items that are not already there for trans_item in reachable { - if let Some(linkage) = old_codegen_unit.items.get(&trans_item) { + if let Some(linkage) = old_codegen_unit.items().get(&trans_item) { // This is a root, just copy it over - new_codegen_unit.items.insert(trans_item, *linkage); + new_codegen_unit.items_mut().insert(trans_item, *linkage); } else { if roots.contains(&trans_item) { bug!("GloballyShared trans-item inlined into other CGU: \ @@ -475,8 +460,10 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit } // This is a cgu-private copy - new_codegen_unit.items.insert(trans_item, - (llvm::InternalLinkage, llvm::Visibility::Default)); + new_codegen_unit.items_mut().insert( + trans_item, + (Linkage::Internal, Visibility::Default), + ); } if !single_codegen_unit { @@ -487,7 +474,7 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit let placement = e.into_mut(); debug_assert!(match *placement { TransItemPlacement::SingleCgu { ref cgu_name } => { - *cgu_name != new_codegen_unit.name + *cgu_name != *new_codegen_unit.name() } TransItemPlacement::MultipleCgus => true, }); @@ -495,7 +482,7 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit } Entry::Vacant(e) => { e.insert(TransItemPlacement::SingleCgu { - cgu_name: new_codegen_unit.name.clone() + cgu_name: new_codegen_unit.name().clone() }); } } @@ -533,8 +520,8 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, // could be accessed from. for cgu in &mut partitioning.codegen_units { for candidate in &partitioning.internalization_candidates { - cgu.items.insert(*candidate, (llvm::InternalLinkage, - llvm::Visibility::Default)); + cgu.items_mut().insert(*candidate, + (Linkage::Internal, Visibility::Default)); } } @@ -558,10 +545,10 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, // accessed from outside its defining codegen unit. for cgu in &mut partitioning.codegen_units { let home_cgu = TransItemPlacement::SingleCgu { - cgu_name: cgu.name.clone() + cgu_name: cgu.name().clone() }; - for (accessee, linkage_and_visibility) in &mut cgu.items { + for (accessee, linkage_and_visibility) in cgu.items_mut() { if !partitioning.internalization_candidates.contains(accessee) { // This item is no candidate for internalizing, so skip it. continue @@ -584,7 +571,7 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, // If we got here, we did not find any accesses from other CGUs, // so it's fine to make this translation item internal. - *linkage_and_visibility = (llvm::InternalLinkage, llvm::Visibility::Default); + *linkage_and_visibility = (Linkage::Internal, Visibility::Default); } } } @@ -675,9 +662,9 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if cfg!(debug_assertions) { debug!("{}", label); for cgu in cgus { - debug!("CodegenUnit {}:", cgu.name); + debug!("CodegenUnit {}:", cgu.name()); - for (trans_item, linkage) in &cgu.items { + for (trans_item, linkage) in cgu.items() { let symbol_name = trans_item.symbol_name(tcx); let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..]) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 5a51f690c45f1..526b61303e153 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -25,23 +25,19 @@ use llvm; use monomorphize::Instance; use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::middle::trans::{Linkage, Visibility}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::{Subst, Substs}; -use syntax::ast::{self, NodeId}; +use syntax::ast; use syntax::attr; use syntax_pos::Span; use syntax_pos::symbol::Symbol; use type_of; -use std::fmt::Write; +use std::fmt::{self, Write}; use std::iter; -#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] -pub enum TransItem<'tcx> { - Fn(Instance<'tcx>), - Static(NodeId), - GlobalAsm(NodeId), -} +pub use rustc::middle::trans::TransItem; /// Describes how a translation item will be instantiated in object files. #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] @@ -55,15 +51,16 @@ pub enum InstantiationMode { LocalCopy, } -impl<'a, 'tcx> TransItem<'tcx> { +pub trait TransItemExt<'a, 'tcx>: fmt::Debug { + fn as_trans_item(&self) -> &TransItem<'tcx>; - pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) { + fn define(&self, ccx: &CrateContext<'a, 'tcx>) { debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(ccx.tcx()), - self.to_raw_string(), - ccx.codegen_unit().name()); + self.to_string(ccx.tcx()), + self.to_raw_string(), + ccx.codegen_unit().name()); - match *self { + match *self.as_trans_item() { TransItem::Static(node_id) => { let tcx = ccx.tcx(); let item = tcx.hir.expect_item(node_id); @@ -97,10 +94,10 @@ impl<'a, 'tcx> TransItem<'tcx> { ccx.codegen_unit().name()); } - pub fn predefine(&self, - ccx: &CrateContext<'a, 'tcx>, - linkage: llvm::Linkage, - visibility: llvm::Visibility) { + fn predefine(&self, + ccx: &CrateContext<'a, 'tcx>, + linkage: Linkage, + visibility: Visibility) { debug!("BEGIN PREDEFINING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), @@ -110,12 +107,12 @@ impl<'a, 'tcx> TransItem<'tcx> { debug!("symbol {}", &symbol_name); - match *self { + match *self.as_trans_item() { TransItem::Static(node_id) => { - TransItem::predefine_static(ccx, node_id, linkage, visibility, &symbol_name); + predefine_static(ccx, node_id, linkage, visibility, &symbol_name); } TransItem::Fn(instance) => { - TransItem::predefine_fn(ccx, instance, linkage, visibility, &symbol_name); + predefine_fn(ccx, instance, linkage, visibility, &symbol_name); } TransItem::GlobalAsm(..) => {} } @@ -126,75 +123,8 @@ impl<'a, 'tcx> TransItem<'tcx> { ccx.codegen_unit().name()); } - fn predefine_static(ccx: &CrateContext<'a, 'tcx>, - node_id: ast::NodeId, - linkage: llvm::Linkage, - visibility: llvm::Visibility, - symbol_name: &str) { - let def_id = ccx.tcx().hir.local_def_id(node_id); - let instance = Instance::mono(ccx.tcx(), def_id); - let ty = common::instance_ty(ccx.tcx(), &instance); - let llty = type_of::type_of(ccx, ty); - - let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { - ccx.sess().span_fatal(ccx.tcx().hir.span(node_id), - &format!("symbol `{}` is already defined", symbol_name)) - }); - - unsafe { - llvm::LLVMRustSetLinkage(g, linkage); - llvm::LLVMRustSetVisibility(g, visibility); - } - - ccx.instances().borrow_mut().insert(instance, g); - ccx.statics().borrow_mut().insert(g, def_id); - } - - fn predefine_fn(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>, - linkage: llvm::Linkage, - visibility: llvm::Visibility, - symbol_name: &str) { - assert!(!instance.substs.needs_infer() && - !instance.substs.has_param_types()); - - let mono_ty = common::instance_ty(ccx.tcx(), &instance); - let attrs = instance.def.attrs(ccx.tcx()); - let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); - unsafe { llvm::LLVMRustSetLinkage(lldecl, linkage) }; - base::set_link_section(ccx, lldecl, &attrs); - if linkage == llvm::Linkage::LinkOnceODRLinkage || - linkage == llvm::Linkage::WeakODRLinkage { - llvm::SetUniqueComdat(ccx.llmod(), lldecl); - } - - // If we're compiling the compiler-builtins crate, e.g. the equivalent of - // compiler-rt, then we want to implicitly compile everything with hidden - // visibility as we're going to link this object all over the place but - // don't want the symbols to get exported. - if linkage != llvm::Linkage::InternalLinkage && - linkage != llvm::Linkage::PrivateLinkage && - attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); - } - } else { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, visibility); - } - } - - debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); - if common::is_inline_instance(ccx.tcx(), &instance) { - attributes::inline(lldecl, attributes::InlineAttr::Hint); - } - attributes::from_fn_attrs(ccx, &attrs, lldecl); - - ccx.instances().borrow_mut().insert(instance, lldecl); - } - - pub fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName { - match *self { + fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName { + match *self.as_trans_item() { TransItem::Fn(instance) => tcx.symbol_name(instance), TransItem::Static(node_id) => { let def_id = tcx.hir.local_def_id(node_id); @@ -209,8 +139,8 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { - match *self { + fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + match *self.as_trans_item() { TransItem::Fn(Instance { def, .. }) => { tcx.hir.as_local_node_id(def.def_id()) } @@ -221,10 +151,10 @@ impl<'a, 'tcx> TransItem<'tcx> { }.map(|node_id| tcx.hir.span(node_id)) } - pub fn instantiation_mode(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> InstantiationMode { - match *self { + fn instantiation_mode(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> InstantiationMode { + match *self.as_trans_item() { TransItem::Fn(ref instance) => { if self.explicit_linkage(tcx).is_none() && common::requests_inline(tcx, instance) @@ -239,8 +169,8 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn is_generic_fn(&self) -> bool { - match *self { + fn is_generic_fn(&self) -> bool { + match *self.as_trans_item() { TransItem::Fn(ref instance) => { instance.substs.types().next().is_some() } @@ -249,8 +179,8 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { - let def_id = match *self { + fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + let def_id = match *self.as_trans_item() { TransItem::Fn(ref instance) => instance.def_id(), TransItem::Static(node_id) => tcx.hir.local_def_id(node_id), TransItem::GlobalAsm(..) => return None, @@ -258,7 +188,7 @@ impl<'a, 'tcx> TransItem<'tcx> { let attributes = tcx.get_attrs(def_id); if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") { - if let Some(linkage) = base::llvm_linkage_by_name(&name.as_str()) { + if let Some(linkage) = base::linkage_by_name(&name.as_str()) { Some(linkage) } else { let span = tcx.hir.span_if_local(def_id); @@ -298,9 +228,9 @@ impl<'a, 'tcx> TransItem<'tcx> { /// Similarly, if a vtable method has such a signature, and therefore can't /// be used, we can just not emit it and have a placeholder (a null pointer, /// which will never be accessed) in its place. - pub fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { debug!("is_instantiable({:?})", self); - let (def_id, substs) = match *self { + let (def_id, substs) = match *self.as_trans_item() { TransItem::Fn(ref instance) => (instance.def_id(), instance.substs), TransItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()), // global asm never has predicates @@ -311,10 +241,10 @@ impl<'a, 'tcx> TransItem<'tcx> { traits::normalize_and_test_predicates(tcx, predicates) } - pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { + fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { let hir_map = &tcx.hir; - return match *self { + return match *self.as_trans_item() { TransItem::Fn(instance) => { to_string_internal(tcx, "fn ", instance) }, @@ -340,8 +270,8 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn to_raw_string(&self) -> String { - match *self { + fn to_raw_string(&self) -> String { + match *self.as_trans_item() { TransItem::Fn(instance) => { format!("Fn({:?}, {})", instance.def, @@ -357,6 +287,77 @@ impl<'a, 'tcx> TransItem<'tcx> { } } +impl<'a, 'tcx> TransItemExt<'a, 'tcx> for TransItem<'tcx> { + fn as_trans_item(&self) -> &TransItem<'tcx> { + self + } +} + +fn predefine_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + node_id: ast::NodeId, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str) { + let def_id = ccx.tcx().hir.local_def_id(node_id); + let instance = Instance::mono(ccx.tcx(), def_id); + let ty = common::instance_ty(ccx.tcx(), &instance); + let llty = type_of::type_of(ccx, ty); + + let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { + ccx.sess().span_fatal(ccx.tcx().hir.span(node_id), + &format!("symbol `{}` is already defined", symbol_name)) + }); + + unsafe { + llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage)); + llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility)); + } + + ccx.instances().borrow_mut().insert(instance, g); + ccx.statics().borrow_mut().insert(g, def_id); +} + +fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: Instance<'tcx>, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str) { + assert!(!instance.substs.needs_infer() && + !instance.substs.has_param_types()); + + let mono_ty = common::instance_ty(ccx.tcx(), &instance); + let attrs = instance.def.attrs(ccx.tcx()); + let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); + unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; + base::set_link_section(ccx, lldecl, &attrs); + if linkage == Linkage::LinkOnceODR || + linkage == Linkage::WeakODR { + llvm::SetUniqueComdat(ccx.llmod(), lldecl); + } + + // If we're compiling the compiler-builtins crate, e.g. the equivalent of + // compiler-rt, then we want to implicitly compile everything with hidden + // visibility as we're going to link this object all over the place but + // don't want the symbols to get exported. + if linkage != Linkage::Internal && linkage != Linkage::Private && + attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") { + unsafe { + llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); + } + } else { + unsafe { + llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility)); + } + } + + debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); + if common::is_inline_instance(ccx.tcx(), &instance) { + attributes::inline(lldecl, attributes::InlineAttr::Hint); + } + attributes::from_fn_attrs(ccx, &attrs, lldecl); + + ccx.instances().borrow_mut().insert(instance, lldecl); +} //=----------------------------------------------------------------------------- // TransItem String Keys From 8821affd1523a719ffb9f6537d53f8725ab00592 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 12 Sep 2017 12:18:11 -0700 Subject: [PATCH 06/11] rustc: Move some attr methods to queries Otherwise we may emit double errors related to the `#[export_name]` attribute, for example, and using a query should ensure that it's only emitted at most once. --- src/librustc/dep_graph/dep_node.rs | 2 ++ src/librustc/middle/reachable.rs | 4 ++-- src/librustc/middle/trans.rs | 10 +++++++++ src/librustc/ty/maps.rs | 2 ++ src/librustc_trans/back/symbol_export.rs | 8 ++------ src/librustc_trans/back/symbol_names.rs | 26 +++++++++++++++++++++++- src/librustc_trans/diagnostics.rs | 24 ++++++++++++++++++++++ src/librustc_trans/lib.rs | 4 ++-- src/libsyntax/attr.rs | 24 ---------------------- src/libsyntax/diagnostic_list.rs | 23 --------------------- 10 files changed, 69 insertions(+), 58 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index afd31306817c0..3a534ef93ad6d 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -577,6 +577,8 @@ define_dep_nodes!( <'tcx> [] AllCrateNums, [] ExportedSymbols, [] CollectAndPartitionTranslationItems, + [] ExportName(DefId), + [] ContainsExternIndicator(DefId), ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index a04ecefce0f36..7c44245090197 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -233,8 +233,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } else { false }; - let is_extern = attr::contains_extern_indicator(&self.tcx.sess.diagnostic(), - &item.attrs); + let def_id = self.tcx.hir.local_def_id(item.id); + let is_extern = self.tcx.contains_extern_indicator(def_id); if reachable || is_extern { self.reachable_symbols.insert(search_item); } diff --git a/src/librustc/middle/trans.rs b/src/librustc/middle/trans.rs index e871a38c4eff0..cf8e9cbbd3d31 100644 --- a/src/librustc/middle/trans.rs +++ b/src/librustc/middle/trans.rs @@ -1,3 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use syntax::ast::NodeId; use syntax::symbol::InternedString; use ty::Instance; diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index c6fff0071bfcb..75c20a25131ab 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -1392,6 +1392,8 @@ define_maps! { <'tcx> [] fn collect_and_partition_translation_items: collect_and_partition_translation_items_node(CrateNum) -> (Arc>>, Vec>>), + [] fn export_name: ExportName(DefId) -> Option, + [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool, } fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index b47d6f8ac2d70..01b8db557bd1b 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -17,7 +17,6 @@ use rustc::ty::TyCtxt; use rustc_allocator::ALLOCATOR_METHODS; use rustc::middle::exported_symbols::{ExportedSymbols, SymbolExportLevel}; use rustc::middle::exported_symbols::is_below_threshold; -use syntax::attr; pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ExportedSymbols { let export_threshold = crates_export_threshold(&tcx.sess.crate_types.borrow()); @@ -137,11 +136,8 @@ pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ExportedSymbols { return ExportedSymbols::new(export_threshold, exports, local_exports); - fn export_level(tcx: TyCtxt, - sym_def_id: DefId) - -> SymbolExportLevel { - let attrs = tcx.get_attrs(sym_def_id); - if attr::contains_extern_indicator(tcx.sess.diagnostic(), &attrs) { + fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { + if tcx.contains_extern_indicator(sym_def_id) { SymbolExportLevel::C } else { SymbolExportLevel::Rust diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index abeb2568cbe1e..306071223fc2c 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -119,6 +119,30 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { def_symbol_name, symbol_name, + + export_name: |tcx, id| { + tcx.get_attrs(id).iter().fold(None, |ia, attr| { + if attr.check_name("export_name") { + if let s @ Some(_) = attr.value_str() { + s + } else { + struct_span_err!(tcx.sess, attr.span, E0558, + "export_name attribute has invalid format") + .span_label(attr.span, "did you mean #[export_name=\"*\"]?") + .emit(); + None + } + } else { + ia + } + }) + }, + + contains_extern_indicator: |tcx, id| { + attr::contains_name(&tcx.get_attrs(id), "no_mangle") || + tcx.export_name(id).is_some() + }, + ..*providers }; } @@ -245,7 +269,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance return tcx.item_name(def_id).to_string(); } - if let Some(name) = attr::find_export_name_attr(tcx.sess.diagnostic(), &attrs) { + if let Some(name) = tcx.export_name(def_id) { // Use provided name return name.to_string(); } diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_trans/diagnostics.rs index df71fd4b19b6a..8485867689129 100644 --- a/src/librustc_trans/diagnostics.rs +++ b/src/librustc_trans/diagnostics.rs @@ -46,4 +46,28 @@ extern "platform-intrinsic" { unsafe { simd_add(i32x1(0), i32x1(1)); } // ok! ``` "##, + +E0558: r##" +The `export_name` attribute was malformed. + +Erroneous code example: + +```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail) +#[export_name] // error: export_name attribute has invalid format +pub fn something() {} + +fn main() {} +``` + +The `export_name` attribute expects a string in order to determine the name of +the exported symbol. Example: + +``` +#[export_name = "some_function"] // ok! +pub fn something() {} + +fn main() {} +``` +"##, + } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 701c7be8ad6d9..42c3e620baa7f 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -76,6 +76,8 @@ use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource}; use rustc::ty::maps::Providers; use rustc::util::nodemap::{FxHashSet, FxHashMap}; +mod diagnostics; + pub mod back { mod archive; mod command; @@ -88,8 +90,6 @@ pub mod back { mod rpath; } -mod diagnostics; - mod abi; mod adt; mod allocator; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 03907eed9006f..36ab3737f3803 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -506,30 +506,6 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { first_attr_value_str_by_name(attrs, "crate_name") } -/// Find the value of #[export_name=*] attribute and check its validity. -pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option { - attrs.iter().fold(None, |ia,attr| { - if attr.check_name("export_name") { - if let s@Some(_) = attr.value_str() { - s - } else { - struct_span_err!(diag, attr.span, E0558, - "export_name attribute has invalid format") - .span_label(attr.span, "did you mean #[export_name=\"*\"]?") - .emit(); - None - } - } else { - ia - } - }) -} - -pub fn contains_extern_indicator(diag: &Handler, attrs: &[Attribute]) -> bool { - contains_name(attrs, "no_mangle") || - find_export_name_attr(diag, attrs).is_some() -} - #[derive(Copy, Clone, PartialEq)] pub enum InlineAttr { None, diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 46dec73c9627d..b29883670bdea 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -219,29 +219,6 @@ Erroneous code example: Delete the offending feature attribute. "##, -E0558: r##" -The `export_name` attribute was malformed. - -Erroneous code example: - -```compile_fail,E0558 -#[export_name] // error: export_name attribute has invalid format -pub fn something() {} - -fn main() {} -``` - -The `export_name` attribute expects a string in order to determine the name of -the exported symbol. Example: - -``` -#[export_name = "some_function"] // ok! -pub fn something() {} - -fn main() {} -``` -"##, - E0565: r##" A literal was used in an attribute that doesn't support literals. From afb85cfd33a6ef52edf8707aea12d952a64bb84c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 13 Sep 2017 13:22:20 -0700 Subject: [PATCH 07/11] rustc: Mostly remove `ExportedSymbols` This is a big map that ends up inside of a `CrateContext` during translation for all codegen units. This means that any change to the map may end up causing an incremental recompilation of a codegen unit! In order to reduce the amount of dependencies here between codegen units and the actual input crate this commit refactors dealing with exported symbols and such into various queries. The new queries are largely based on existing queries with filled out implementations for the local crate in addition to external crates, but the main idea is that while translating codegen untis no unit needs the entire set of exported symbols, instead they only need queries about particulare `DefId` instances every now and then. The linking stage, however, still generates a full list of all exported symbols from all crates, but that's going to always happen unconditionally anyway, so no news there! --- src/librustc/dep_graph/dep_node.rs | 2 +- src/librustc/middle/cstore.rs | 5 +- src/librustc/middle/exported_symbols.rs | 60 +------ src/librustc/ty/context.rs | 6 - src/librustc/ty/maps.rs | 16 +- src/librustc_metadata/decoder.rs | 3 +- src/librustc_trans/back/linker.rs | 49 ++--- src/librustc_trans/back/lto.rs | 15 +- src/librustc_trans/back/symbol_export.rs | 216 +++++++++++++---------- src/librustc_trans/back/write.rs | 46 +++-- src/librustc_trans/base.rs | 71 ++------ src/librustc_trans/callee.rs | 4 +- src/librustc_trans/collector.rs | 12 +- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/context.rs | 12 +- src/librustc_trans/debuginfo/utils.rs | 3 +- src/librustc_trans/lib.rs | 9 +- src/librustc_trans/partitioning.rs | 15 +- 18 files changed, 233 insertions(+), 313 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 3a534ef93ad6d..bfbf280d6ddba 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -575,7 +575,7 @@ define_dep_nodes!( <'tcx> [] MaybeUnusedExternCrates, [] StabilityIndex, [] AllCrateNums, - [] ExportedSymbols, + [] ExportedSymbols(CrateNum), [] CollectAndPartitionTranslationItems, [] ExportName(DefId), [] ContainsExternIndicator(DefId), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index a7d874386d1c9..bea6ef4dc11ce 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -366,8 +366,9 @@ pub trait CrateLoader { // In order to get this left-to-right dependency ordering, we perform a // topological sort of all crates putting the leaves at the right-most // positions. -pub fn used_crates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> { +pub fn used_crates(tcx: TyCtxt, prefer: LinkagePreference) + -> Vec<(CrateNum, LibSource)> +{ let mut libs = tcx.crates() .iter() .cloned() diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs index 7f03f8a5a2986..230878f854595 100644 --- a/src/librustc/middle/exported_symbols.rs +++ b/src/librustc/middle/exported_symbols.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use util::nodemap::{FxHashMap, NodeSet}; -use hir::def_id::{DefId, CrateNum}; - /// The SymbolExportLevel of a symbols specifies from which kinds of crates /// the symbol will be exported. `C` symbols will be exported from any /// kind of crate, including cdylibs which export very few things. @@ -22,56 +19,13 @@ pub enum SymbolExportLevel { Rust, } -/// The set of symbols exported from each crate in the crate graph. -#[derive(Debug)] -pub struct ExportedSymbols { - pub export_threshold: SymbolExportLevel, - exports: FxHashMap>, - local_exports: NodeSet, -} - -impl ExportedSymbols { - pub fn new(export_threshold: SymbolExportLevel, - exports: FxHashMap>, - local_exports: NodeSet) -> ExportedSymbols { - ExportedSymbols { - export_threshold, - exports, - local_exports, - } - } - - pub fn local_exports(&self) -> &NodeSet { - &self.local_exports - } - - pub fn exported_symbols(&self, cnum: CrateNum) - -> &[(String, DefId, SymbolExportLevel)] - { - match self.exports.get(&cnum) { - Some(exports) => exports, - None => &[] - } - } - - pub fn for_each_exported_symbol(&self, cnum: CrateNum, mut f: F) - where F: FnMut(&str, DefId, SymbolExportLevel) - { - for &(ref name, def_id, export_level) in self.exported_symbols(cnum) { - if is_below_threshold(export_level, self.export_threshold) { - f(&name, def_id, export_level) - } +impl SymbolExportLevel { + pub fn is_below_threshold(self, threshold: SymbolExportLevel) -> bool { + if threshold == SymbolExportLevel::Rust { + // We export everything from Rust dylibs + true + } else { + self == SymbolExportLevel::C } } } - -pub fn is_below_threshold(level: SymbolExportLevel, - threshold: SymbolExportLevel) - -> bool { - if threshold == SymbolExportLevel::Rust { - // We export everything from Rust dylibs - true - } else { - level == SymbolExportLevel::C - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index af5c37e0f1605..fb0cdab0b6a0f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -27,7 +27,6 @@ use middle::cstore::EncodedMetadata; use middle::free_region::FreeRegionMap; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; -use middle::exported_symbols::ExportedSymbols; use middle::stability; use mir::Mir; use mir::transform::Passes; @@ -65,7 +64,6 @@ use std::mem; use std::ops::Deref; use std::iter; use std::rc::Rc; -use std::sync::Arc; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; @@ -1220,10 +1218,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn crate_data_as_rc_any(self, cnum: CrateNum) -> Rc { self.cstore.crate_data_as_rc_any(cnum) } - - pub fn exported_symbols(self) -> Arc { - self.exported_symbol_set(LOCAL_CRATE) - } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 75c20a25131ab..dd6d90503ef1b 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -23,7 +23,7 @@ use middle::region; use middle::resolve_lifetime::{Region, ObjectLifetimeDefault}; use middle::stability::{self, DeprecationEntry}; use middle::lang_items::{LanguageItems, LangItem}; -use middle::exported_symbols::ExportedSymbols; +use middle::exported_symbols::SymbolExportLevel; use middle::trans::{TransItem, CodegenUnit}; use mir; use mir::transform::{MirSuite, MirPassIndex}; @@ -748,9 +748,9 @@ impl<'tcx> QueryDescription for queries::all_crate_nums<'tcx> { } } -impl<'tcx> QueryDescription for queries::exported_symbol_set<'tcx> { +impl<'tcx> QueryDescription for queries::exported_symbols<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("exported symbol set") + format!("exported_symbols") } } @@ -1337,7 +1337,7 @@ define_maps! { <'tcx> [] fn lint_levels: lint_levels_node(CrateNum) -> Rc, [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, - [] fn exported_symbol_ids: ExportedSymbolIds(CrateNum) -> Rc>, + [] fn exported_symbol_ids: ExportedSymbolIds(CrateNum) -> Rc, [] fn native_libraries: NativeLibraries(CrateNum) -> Rc>, [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option, [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option, @@ -1387,8 +1387,8 @@ define_maps! { <'tcx> [] fn stability_index: stability_index_node(CrateNum) -> Rc>, [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Rc>, - [] fn exported_symbol_set: exported_symbol_set_node(CrateNum) - -> Arc, + [] fn exported_symbols: ExportedSymbols(CrateNum) + -> Arc>, [] fn collect_and_partition_translation_items: collect_and_partition_translation_items_node(CrateNum) -> (Arc>>, Vec>>), @@ -1508,10 +1508,6 @@ fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::AllCrateNums } -fn exported_symbol_set_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::ExportedSymbols -} - fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::CollectAndPartitionTranslationItems } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 689f9f5b24430..1c4f1c6348689 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -24,6 +24,7 @@ use rustc::middle::lang_items; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; +use rustc::util::nodemap::DefIdSet; use rustc::mir::Mir; @@ -1017,7 +1018,7 @@ impl<'a, 'tcx> CrateMetadata { arg_names.decode(self).collect() } - pub fn get_exported_symbols(&self) -> Vec { + pub fn get_exported_symbols(&self) -> DefIdSet { self.exported_symbols .iter() .map(|&index| self.local_def_id(index)) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 1eb3e86a15b81..239b488fabe0f 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -15,16 +15,15 @@ use std::io::prelude::*; use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; -use context::SharedCrateContext; - use back::archive; use back::command::Command; -use rustc::middle::dependency_format::Linkage; -use rustc::middle::exported_symbols::ExportedSymbols; +use back::symbol_export; use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; -use rustc_back::LinkerFlavor; +use rustc::middle::dependency_format::Linkage; use rustc::session::Session; use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel}; +use rustc::ty::TyCtxt; +use rustc_back::LinkerFlavor; use serialize::{json, Encoder}; /// For all the linkers we support, and information they might @@ -33,19 +32,18 @@ pub struct LinkerInfo { exports: HashMap>, } -impl<'a, 'tcx> LinkerInfo { - pub fn new(scx: &SharedCrateContext<'a, 'tcx>) -> LinkerInfo { - let exports = scx.tcx().exported_symbols(); +impl LinkerInfo { + pub fn new(tcx: TyCtxt) -> LinkerInfo { LinkerInfo { - exports: scx.sess().crate_types.borrow().iter().map(|&c| { - (c, exported_symbols(scx, &exports, c)) + exports: tcx.sess.crate_types.borrow().iter().map(|&c| { + (c, exported_symbols(tcx, c)) }).collect(), } } - pub fn to_linker(&'a self, - cmd: Command, - sess: &'a Session) -> Box { + pub fn to_linker<'a>(&'a self, + cmd: Command, + sess: &'a Session) -> Box { match sess.linker_flavor() { LinkerFlavor::Msvc => { Box::new(MsvcLinker { @@ -734,16 +732,17 @@ impl<'a> Linker for EmLinker<'a> { } } -fn exported_symbols(scx: &SharedCrateContext, - exported_symbols: &ExportedSymbols, - crate_type: CrateType) - -> Vec { +fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { let mut symbols = Vec::new(); - exported_symbols.for_each_exported_symbol(LOCAL_CRATE, |name, _, _| { - symbols.push(name.to_owned()); - }); - let formats = scx.sess().dependency_formats.borrow(); + let export_threshold = symbol_export::threshold(tcx); + for &(ref name, _, level) in tcx.exported_symbols(LOCAL_CRATE).iter() { + if level.is_below_threshold(export_threshold) { + symbols.push(name.clone()); + } + } + + let formats = tcx.sess.dependency_formats.borrow(); let deps = formats[&crate_type].iter(); for (index, dep_format) in deps.enumerate() { @@ -751,9 +750,11 @@ fn exported_symbols(scx: &SharedCrateContext, // For each dependency that we are linking to statically ... if *dep_format == Linkage::Static { // ... we add its symbol list to our export list. - exported_symbols.for_each_exported_symbol(cnum, |name, _, _| { - symbols.push(name.to_owned()); - }) + for &(ref name, _, level) in tcx.exported_symbols(cnum).iter() { + if level.is_below_threshold(export_threshold) { + symbols.push(name.clone()); + } + } } } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 125b07a9505b1..aa13e4aa196ee 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -16,7 +16,7 @@ use errors::{FatalError, Handler}; use llvm; use llvm::archive_ro::ArchiveRO; use llvm::{ModuleRef, TargetMachineRef, True, False}; -use rustc::middle::exported_symbols; +use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::util::common::time; use rustc::util::common::path2cstr; use rustc::hir::def_id::LOCAL_CRATE; @@ -68,8 +68,8 @@ pub fn run(cgcx: &CodegenContext, let export_threshold = symbol_export::crates_export_threshold(&cgcx.crate_types); - let symbol_filter = &|&(ref name, _, level): &(String, _, _)| { - if exported_symbols::is_below_threshold(level, export_threshold) { + let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| { + if level.is_below_threshold(export_threshold) { let mut bytes = Vec::with_capacity(name.len() + 1); bytes.extend(name.bytes()); Some(CString::new(bytes).unwrap()) @@ -78,8 +78,7 @@ pub fn run(cgcx: &CodegenContext, } }; - let mut symbol_white_list: Vec = cgcx.exported_symbols - .exported_symbols(LOCAL_CRATE) + let mut symbol_white_list: Vec = cgcx.exported_symbols[&LOCAL_CRATE] .iter() .filter_map(symbol_filter) .collect(); @@ -89,9 +88,9 @@ pub fn run(cgcx: &CodegenContext, // module that we've got. for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { symbol_white_list.extend( - cgcx.exported_symbols.exported_symbols(cnum) - .iter() - .filter_map(symbol_filter)); + cgcx.exported_symbols[&cnum] + .iter() + .filter_map(symbol_filter)); let archive = ArchiveRO::open(&path).expect("wanted an rlib"); let bytecodes = archive.iter().filter_map(|child| { diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 01b8db557bd1b..844442edbc872 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -8,89 +8,140 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::rc::Rc; +use std::sync::Arc; + use base; use monomorphize::Instance; -use rustc::util::nodemap::{FxHashMap, NodeSet}; +use rustc::hir::def_id::CrateNum; use rustc::hir::def_id::{DefId, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX}; +use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config; use rustc::ty::TyCtxt; +use rustc::ty::maps::Providers; +use rustc::util::nodemap::FxHashMap; use rustc_allocator::ALLOCATOR_METHODS; -use rustc::middle::exported_symbols::{ExportedSymbols, SymbolExportLevel}; -use rustc::middle::exported_symbols::is_below_threshold; -pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ExportedSymbols { - let export_threshold = crates_export_threshold(&tcx.sess.crate_types.borrow()); - let local_exported_symbols = base::find_exported_symbols(tcx); +pub type ExportedSymbols = FxHashMap< + CrateNum, + Arc>, +>; - let mut local_crate: Vec<_> = local_exported_symbols - .iter() - .map(|&node_id| { - tcx.hir.local_def_id(node_id) - }) - .map(|def_id| { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)); - let export_level = export_level(tcx, def_id); - debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level); - (str::to_owned(&name), def_id, export_level) - }) - .collect(); - - let mut local_exports = local_crate - .iter() - .filter_map(|&(_, def_id, level)| { - if is_below_threshold(level, export_threshold) { - tcx.hir.as_local_node_id(def_id) - } else { - None - } - }) - .collect::(); +pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel { + crates_export_threshold(&tcx.sess.crate_types.borrow()) +} - const INVALID_DEF_ID: DefId = DefId { - krate: INVALID_CRATE, - index: CRATE_DEF_INDEX, - }; +pub fn metadata_symbol_name(tcx: TyCtxt) -> String { + format!("rust_metadata_{}_{}", + tcx.crate_name(LOCAL_CRATE), + tcx.crate_disambiguator(LOCAL_CRATE)) +} - if let Some(_) = *tcx.sess.entry_fn.borrow() { - local_crate.push(("main".to_string(), - INVALID_DEF_ID, - SymbolExportLevel::C)); +fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel { + match crate_type { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeProcMacro | + config::CrateTypeCdylib => SymbolExportLevel::C, + config::CrateTypeRlib | + config::CrateTypeDylib => SymbolExportLevel::Rust, } +} - if tcx.sess.allocator_kind.get().is_some() { - for method in ALLOCATOR_METHODS { - local_crate.push((format!("__rust_{}", method.name), - INVALID_DEF_ID, - SymbolExportLevel::Rust)); - } +pub fn crates_export_threshold(crate_types: &[config::CrateType]) + -> SymbolExportLevel { + if crate_types.iter().any(|&crate_type| { + crate_export_threshold(crate_type) == SymbolExportLevel::Rust + }) { + SymbolExportLevel::Rust + } else { + SymbolExportLevel::C } +} - if let Some(id) = tcx.sess.derive_registrar_fn.get() { - let def_id = tcx.hir.local_def_id(id); - let idx = def_id.index; - let disambiguator = tcx.sess.local_crate_disambiguator(); - let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx); - local_crate.push((registrar, def_id, SymbolExportLevel::C)); - local_exports.insert(id); - } +pub fn provide_local(providers: &mut Providers) { + providers.exported_symbol_ids = |tcx, cnum| { + let export_threshold = threshold(tcx); + Rc::new(tcx.exported_symbols(cnum) + .iter() + .filter_map(|&(_, id, level)| { + if level.is_below_threshold(export_threshold) { + Some(id) + } else { + None + } + }) + .collect()) + }; - if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) { - local_crate.push((metadata_symbol_name(tcx), - INVALID_DEF_ID, - SymbolExportLevel::Rust)); - } + providers.is_exported_symbol = |tcx, id| { + // FIXME(#42293) needs red/green to not break a bunch of incremental + // tests + tcx.dep_graph.with_ignore(|| { + tcx.exported_symbol_ids(id.krate).contains(&id) + }) + }; + + providers.exported_symbols = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + let local_exported_symbols = base::find_exported_symbols(tcx); + + let mut local_crate: Vec<_> = local_exported_symbols + .iter() + .map(|&node_id| { + tcx.hir.local_def_id(node_id) + }) + .map(|def_id| { + let name = tcx.symbol_name(Instance::mono(tcx, def_id)); + let export_level = export_level(tcx, def_id); + debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level); + (str::to_owned(&name), def_id, export_level) + }) + .collect(); + + const INVALID_DEF_ID: DefId = DefId { + krate: INVALID_CRATE, + index: CRATE_DEF_INDEX, + }; + + if let Some(_) = *tcx.sess.entry_fn.borrow() { + local_crate.push(("main".to_string(), + INVALID_DEF_ID, + SymbolExportLevel::C)); + } - let mut exports = FxHashMap(); - exports.insert(LOCAL_CRATE, local_crate); + if tcx.sess.allocator_kind.get().is_some() { + for method in ALLOCATOR_METHODS { + local_crate.push((format!("__rust_{}", method.name), + INVALID_DEF_ID, + SymbolExportLevel::Rust)); + } + } - for &cnum in tcx.crates().iter() { - debug_assert!(cnum != LOCAL_CRATE); + if let Some(id) = tcx.sess.derive_registrar_fn.get() { + let def_id = tcx.hir.local_def_id(id); + let idx = def_id.index; + let disambiguator = tcx.sess.local_crate_disambiguator(); + let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx); + local_crate.push((registrar, def_id, SymbolExportLevel::C)); + } + if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) { + local_crate.push((metadata_symbol_name(tcx), + INVALID_DEF_ID, + SymbolExportLevel::Rust)); + } + Arc::new(local_crate) + }; +} + +pub fn provide_extern(providers: &mut Providers) { + providers.exported_symbols = |tcx, cnum| { // If this crate is a plugin and/or a custom derive crate, then // we're not even going to link those in so we skip those crates. if tcx.plugin_registrar_fn(cnum).is_some() || tcx.derive_registrar_fn(cnum).is_some() { - continue; + return Arc::new(Vec::new()) } // Check to see if this crate is a "special runtime crate". These @@ -131,45 +182,14 @@ pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ExportedSymbols { }) .collect(); - exports.insert(cnum, crate_exports); - } - - return ExportedSymbols::new(export_threshold, exports, local_exports); - - fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { - if tcx.contains_extern_indicator(sym_def_id) { - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust - } - } -} - -pub fn metadata_symbol_name(tcx: TyCtxt) -> String { - format!("rust_metadata_{}_{}", - tcx.crate_name(LOCAL_CRATE), - tcx.crate_disambiguator(LOCAL_CRATE)) -} - -pub fn crate_export_threshold(crate_type: config::CrateType) - -> SymbolExportLevel { - match crate_type { - config::CrateTypeExecutable | - config::CrateTypeStaticlib | - config::CrateTypeProcMacro | - config::CrateTypeCdylib => SymbolExportLevel::C, - config::CrateTypeRlib | - config::CrateTypeDylib => SymbolExportLevel::Rust, - } + Arc::new(crate_exports) + }; } -pub fn crates_export_threshold(crate_types: &[config::CrateType]) - -> SymbolExportLevel { - if crate_types.iter().any(|&crate_type| { - crate_export_threshold(crate_type) == SymbolExportLevel::Rust - }) { - SymbolExportLevel::Rust - } else { +fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { + if tcx.contains_extern_indicator(sym_def_id) { SymbolExportLevel::C + } else { + SymbolExportLevel::Rust } } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index d241edca0ead7..c8925ceb478ce 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -11,24 +11,27 @@ use back::lto; use back::link::{self, get_linker, remove}; use back::linker::LinkerInfo; -use rustc::middle::exported_symbols::ExportedSymbols; +use back::symbol_export::ExportedSymbols; use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; use rustc::dep_graph::DepGraph; use rustc::middle::cstore::{LinkMeta, EncodedMetadata}; use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses, AllPasses, Sanitizer}; use rustc::session::Session; +use rustc::util::nodemap::FxHashMap; use time_graph::{self, TimeGraph}; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef}; use llvm::SMDiagnosticRef; use {CrateTranslation, ModuleSource, ModuleTranslation, CompiledModule, ModuleKind}; use CrateInfo; -use rustc::hir::def_id::CrateNum; +use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; +use rustc::ty::TyCtxt; use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry}; use rustc::util::fs::{link_or_copy, rename_or_copy_remove}; use errors::{self, Handler, Level, DiagnosticBuilder, FatalError}; use errors::emitter::{Emitter}; +use syntax::attr; use syntax::ext::hygiene::Mark; use syntax_pos::MultiSpan; use syntax_pos::symbol::Symbol; @@ -667,19 +670,40 @@ fn need_crate_bitcode_for_rlib(sess: &Session) -> bool { sess.opts.output_types.contains_key(&OutputType::Exe) } -pub fn start_async_translation(sess: &Session, +pub fn start_async_translation(tcx: TyCtxt, crate_output: &OutputFilenames, time_graph: Option, - crate_name: Symbol, link: LinkMeta, - metadata: EncodedMetadata, - exported_symbols: Arc, - no_builtins: bool, - windows_subsystem: Option, - linker_info: LinkerInfo, - crate_info: CrateInfo, - no_integrated_as: bool) + metadata: EncodedMetadata) -> OngoingCrateTranslation { + let sess = tcx.sess; + let crate_name = tcx.crate_name(LOCAL_CRATE); + let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins"); + let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs, + "windows_subsystem"); + let windows_subsystem = subsystem.map(|subsystem| { + if subsystem != "windows" && subsystem != "console" { + tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ + `windows` and `console` are allowed", + subsystem)); + } + subsystem.to_string() + }); + + let no_integrated_as = tcx.sess.opts.cg.no_integrated_as || + (tcx.sess.target.target.options.no_integrated_as && + (crate_output.outputs.contains_key(&OutputType::Object) || + crate_output.outputs.contains_key(&OutputType::Exe))); + let linker_info = LinkerInfo::new(tcx); + let crate_info = CrateInfo::new(tcx); + + let mut exported_symbols = FxHashMap(); + exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE)); + for &cnum in tcx.crates().iter() { + exported_symbols.insert(cnum, tcx.exported_symbols(cnum)); + } + let exported_symbols = Arc::new(exported_symbols); + let output_types_override = if no_integrated_as { OutputTypes::new(&[(OutputType::Assembly, None)]) } else { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 7d0e7c210746b..7941134cc7b07 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -30,7 +30,6 @@ use super::ModuleKind; use assert_module_sources; use back::link; -use back::linker::LinkerInfo; use back::symbol_export; use back::write::{self, OngoingCrateTranslation}; use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; @@ -44,10 +43,9 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::dep_graph::AssertDepGraphSafe; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; -use rustc::middle::exported_symbols::ExportedSymbols; use rustc::hir::map as hir_map; use rustc::util::common::{time, print_time_passes_entry}; -use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType}; +use rustc::session::config::{self, NoDebugInfo, OutputFilenames}; use rustc::session::Session; use rustc_incremental::{self, IncrementalHashesMap}; use abi; @@ -939,11 +937,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> OngoingCrateTranslation { check_for_rustc_errors_attr(tcx); - // Be careful with this krate: obviously it gives access to the - // entire contents of the krate. So if you push any subtasks of - // `TransCrate`, you need to be careful to register "reads" of the - // particular items that will be processed. - let krate = tcx.hir.krate(); let check_overflow = tcx.sess.overflow_checks(); let link_meta = link::build_link_meta(&incremental_hashes_map); let exported_symbol_node_ids = find_exported_symbols(tcx); @@ -967,31 +960,21 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, kind: ModuleKind::Metadata, }; - let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); let time_graph = if tcx.sess.opts.debugging_opts.trans_time_graph { Some(time_graph::TimeGraph::new()) } else { None }; - let crate_info = CrateInfo::new(tcx); // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.debugging_opts.no_trans || !tcx.sess.opts.output_types.should_trans() { - let linker_info = LinkerInfo::new(&shared_ccx); let ongoing_translation = write::start_async_translation( - tcx.sess, + tcx, output_filenames, time_graph.clone(), - tcx.crate_name(LOCAL_CRATE), link_meta, - metadata, - shared_ccx.tcx().exported_symbols(), - no_builtins, - None, - linker_info, - crate_info, - false); + metadata); ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, metadata_module, true); @@ -1012,36 +995,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert!(codegen_units.len() <= 1 || !tcx.sess.lto()); - let linker_info = LinkerInfo::new(&shared_ccx); - let subsystem = attr::first_attr_value_str_by_name(&krate.attrs, - "windows_subsystem"); - let windows_subsystem = subsystem.map(|subsystem| { - if subsystem != "windows" && subsystem != "console" { - tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ - `windows` and `console` are allowed", - subsystem)); - } - subsystem.to_string() - }); - - let no_integrated_as = tcx.sess.opts.cg.no_integrated_as || - (tcx.sess.target.target.options.no_integrated_as && - (output_filenames.outputs.contains_key(&OutputType::Object) || - output_filenames.outputs.contains_key(&OutputType::Exe))); - let ongoing_translation = write::start_async_translation( - tcx.sess, + tcx, output_filenames, time_graph.clone(), - tcx.crate_name(LOCAL_CRATE), link_meta, - metadata, - tcx.exported_symbols(), - no_builtins, - windows_subsystem, - linker_info, - crate_info, - no_integrated_as); + metadata); // Translate an allocator shim, if any // @@ -1118,8 +1077,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.dep_graph.with_task(dep_node, AssertDepGraphSafe(&shared_ccx), AssertDepGraphSafe((cgu, - translation_items.clone(), - tcx.exported_symbols())), + translation_items.clone())), module_translation); all_stats.extend(stats); @@ -1161,13 +1119,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn module_translation<'a, 'tcx>( scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, args: AssertDepGraphSafe<(Arc>, - Arc>>, - Arc)>) + Arc>>)>) -> (Stats, ModuleTranslation) { // FIXME(#40304): We ought to be using the id as a key and some queries, I think. let AssertDepGraphSafe(scx) = scx; - let AssertDepGraphSafe((cgu, crate_trans_items, exported_symbols)) = args; + let AssertDepGraphSafe((cgu, crate_trans_items)) = args; let cgu_name = cgu.name().to_string(); let cgu_id = cgu.work_product_id(); @@ -1207,7 +1164,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Instantiate translation items without filling out definitions yet... - let lcx = LocalCrateContext::new(scx, cgu, crate_trans_items, exported_symbols); + let lcx = LocalCrateContext::new(scx, cgu, crate_trans_items); let module = { let ccx = CrateContext::new(scx, &lcx); let trans_items = ccx.codegen_unit() @@ -1400,7 +1357,6 @@ fn collect_and_partition_translation_items<'a, 'tcx>( { assert_eq!(cnum, LOCAL_CRATE); let time_passes = tcx.sess.time_passes(); - let exported_symbols = tcx.exported_symbols(); let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items { Some(ref s) => { @@ -1424,9 +1380,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( let (items, inlining_map) = time(time_passes, "translation item collection", || { - collector::collect_crate_translation_items(tcx, - &exported_symbols, - collection_mode) + collector::collect_crate_translation_items(tcx, collection_mode) }); assert_symbols_are_distinct(tcx, items.iter()); @@ -1441,8 +1395,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( partitioning::partition(tcx, items.iter().cloned(), strategy, - &inlining_map, - &exported_symbols) + &inlining_map) .into_iter() .map(Arc::new) .collect::>() @@ -1510,7 +1463,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( } impl CrateInfo { - pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CrateInfo { + pub fn new(tcx: TyCtxt) -> CrateInfo { let mut info = CrateInfo { panic_runtime: None, compiler_builtins: None, diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index ffdd76dd68731..a904aa7ed876a 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -114,8 +114,8 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); if ccx.crate_trans_items().contains(&TransItem::Fn(instance)) { - if let Some(node_id) = tcx.hir.as_local_node_id(instance_def_id) { - if !ccx.exported_symbols().local_exports().contains(&node_id) { + if instance_def_id.is_local() { + if !ccx.tcx().is_exported_symbol(instance_def_id) { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } else { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index a45bcb51ab594..6fa69de74b0a1 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -194,7 +194,6 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; -use rustc::middle::exported_symbols::ExportedSymbols; use rustc::middle::lang_items::{ExchangeMallocFnLangItem}; use rustc::traits; use rustc::ty::subst::Substs; @@ -294,14 +293,13 @@ impl<'tcx> InliningMap<'tcx> { } pub fn collect_crate_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - exported_symbols: &ExportedSymbols, mode: TransItemCollectionMode) -> (FxHashSet>, InliningMap<'tcx>) { // We are not tracking dependencies of this pass as it has to be re-executed // every time no matter what. tcx.dep_graph.with_ignore(|| { - let roots = collect_roots(tcx, exported_symbols, mode); + let roots = collect_roots(tcx, mode); debug!("Building translation item graph, beginning at roots"); let mut visited = FxHashSet(); @@ -323,7 +321,6 @@ pub fn collect_crate_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Find all non-generic items by walking the HIR. These items serve as roots to // start monomorphizing from. fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - exported_symbols: &ExportedSymbols, mode: TransItemCollectionMode) -> Vec> { debug!("Collecting roots"); @@ -333,7 +330,6 @@ fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut visitor = RootCollector { tcx, mode, - exported_symbols, output: &mut roots, }; @@ -865,7 +861,6 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - exported_symbols: &'b ExportedSymbols, mode: TransItemCollectionMode, output: &'b mut Vec>, } @@ -926,8 +921,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { let def_id = tcx.hir.local_def_id(item.id); if (self.mode == TransItemCollectionMode::Eager || - !tcx.is_const_fn(def_id) || - self.exported_symbols.local_exports().contains(&item.id)) && + !tcx.is_const_fn(def_id) || tcx.is_exported_symbol(def_id)) && !item_has_type_parameters(tcx, def_id) { debug!("RootCollector: ItemFn({})", @@ -953,7 +947,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { if (self.mode == TransItemCollectionMode::Eager || !tcx.is_const_fn(def_id) || - self.exported_symbols.local_exports().contains(&ii.id)) && + tcx.is_exported_symbol(def_id)) && !item_has_type_parameters(tcx, def_id) { debug!("RootCollector: MethodImplItem({})", def_id_to_string(tcx, def_id)); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 4f78e77fc690c..78ece020d1d6b 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -130,7 +130,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { let g = declare::define_global(ccx, &sym[..], llty).unwrap(); - if !ccx.exported_symbols().local_exports().contains(&id) { + if !ccx.tcx().is_exported_symbol(def_id) { unsafe { llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 7a2db29705d83..62dadce76f0e7 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -14,7 +14,6 @@ use llvm::{ContextRef, ModuleRef, ValueRef}; use rustc::dep_graph::{DepGraph, DepGraphSafe}; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::middle::exported_symbols::ExportedSymbols; use rustc::traits; use debuginfo; use callee; @@ -98,9 +97,6 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> { /// The translation items of the whole crate. crate_trans_items: Arc>>, - /// Information about which symbols are exported from the crate. - exported_symbols: Arc, - /// Cache instances of monomorphic and polymorphic items instances: RefCell, ValueRef>>, /// Cache generated vtables @@ -354,8 +350,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { pub fn new(shared: &SharedCrateContext<'a, 'tcx>, codegen_unit: Arc>, - crate_trans_items: Arc>>, - exported_symbols: Arc,) + crate_trans_items: Arc>>) -> LocalCrateContext<'a, 'tcx> { unsafe { // Append ".rs" to LLVM module identifier. @@ -388,7 +383,6 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { stats: Stats::default(), codegen_unit, crate_trans_items, - exported_symbols, instances: RefCell::new(FxHashMap()), vtables: RefCell::new(FxHashMap()), const_cstr_cache: RefCell::new(FxHashMap()), @@ -499,10 +493,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().crate_trans_items } - pub fn exported_symbols(&self) -> &ExportedSymbols { - &self.local().exported_symbols - } - pub fn td(&self) -> llvm::TargetDataRef { unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } } diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 7529139c05aac..ad4fdfca7261f 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -37,7 +37,8 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool // visible). It might better to use the `exported_items` set from // `driver::CrateAnalysis` in the future, but (atm) this set is not // available in the translation pass. - !cx.exported_symbols().local_exports().contains(&node_id) + let def_id = cx.tcx().hir.local_def_id(node_id); + !cx.tcx().is_exported_symbol(def_id) } #[allow(non_snake_case)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 42c3e620baa7f..d06c769458a74 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -69,9 +69,8 @@ pub use metadata::LlvmMetadataLoader; pub use llvm_util::{init, target_features, print_version, print_passes, print, enable_llvm_debug}; use std::rc::Rc; -use std::sync::Arc; -use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; +use rustc::hir::def_id::CrateNum; use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource}; use rustc::ty::maps::Providers; use rustc::util::nodemap::{FxHashSet, FxHashMap}; @@ -251,13 +250,11 @@ __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } pub fn provide_local(providers: &mut Providers) { back::symbol_names::provide(providers); + back::symbol_export::provide_local(providers); base::provide(providers); - providers.exported_symbol_set = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - Arc::new(back::symbol_export::compute(tcx)) - }; } pub fn provide_extern(providers: &mut Providers) { back::symbol_names::provide(providers); + back::symbol_export::provide_extern(providers); } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index d4aecb9e56caa..65cf24e8c6e03 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -108,7 +108,6 @@ use context::SharedCrateContext; use rustc::dep_graph::{DepNode, WorkProductId}; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; -use rustc::middle::exported_symbols::ExportedSymbols; use rustc::middle::trans::{Linkage, Visibility}; use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER; use rustc::ty::{self, TyCtxt, InstanceDef}; @@ -212,8 +211,7 @@ const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I, strategy: PartitioningStrategy, - inlining_map: &InliningMap<'tcx>, - exported_symbols: &ExportedSymbols) + inlining_map: &InliningMap<'tcx>) -> Vec> where I: Iterator> { @@ -221,7 +219,6 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. let mut initial_partitioning = place_root_translation_items(tcx, - exported_symbols, trans_items); debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); @@ -291,13 +288,10 @@ struct PostInliningPartitioning<'tcx> { } fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - exported_symbols: &ExportedSymbols, trans_items: I) -> PreInliningPartitioning<'tcx> where I: Iterator> { - let exported_symbols = exported_symbols.local_exports(); - let mut roots = FxHashSet(); let mut codegen_units = FxHashMap(); let is_incremental_build = tcx.sess.opts.incremental.is_some(); @@ -330,8 +324,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, TransItem::Fn(ref instance) => { let visibility = match instance.def { InstanceDef::Item(def_id) => { - if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - if exported_symbols.contains(&node_id) { + if def_id.is_local() { + if tcx.is_exported_symbol(def_id) { Visibility::Default } else { internalization_candidates.insert(trans_item); @@ -357,7 +351,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } TransItem::Static(node_id) | TransItem::GlobalAsm(node_id) => { - let visibility = if exported_symbols.contains(&node_id) { + let def_id = tcx.hir.local_def_id(node_id); + let visibility = if tcx.is_exported_symbol(def_id) { Visibility::Default } else { internalization_candidates.insert(trans_item); From 19727c84dde781abf3a534be0308b1cd55a88cf7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 13 Sep 2017 15:04:51 -0700 Subject: [PATCH 08/11] rustc: Move a comment to the right spot in trans I believe this comment here is mostly talking about the `ptrcast` function call below, so move the comment down to that block. --- src/librustc_trans/callee.rs | 47 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index a904aa7ed876a..b62d60db23a98 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -53,35 +53,34 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let sym = tcx.symbol_name(instance); debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); - // This is subtle and surprising, but sometimes we have to bitcast - // the resulting fn pointer. The reason has to do with external - // functions. If you have two crates that both bind the same C - // library, they may not use precisely the same types: for - // example, they will probably each declare their own structs, - // which are distinct types from LLVM's point of view (nominal - // types). - // - // Now, if those two crates are linked into an application, and - // they contain inlined code, you can wind up with a situation - // where both of those functions wind up being loaded into this - // application simultaneously. In that case, the same function - // (from LLVM's point of view) requires two types. But of course - // LLVM won't allow one function to have two types. - // - // What we currently do, therefore, is declare the function with - // one of the two types (whichever happens to come first) and then - // bitcast as needed when the function is referenced to make sure - // it has the type we expect. - // - // This can occur on either a crate-local or crate-external - // reference. It also occurs when testing libcore and in some - // other weird situations. Annoying. - // Create a fn pointer with the substituted signature. let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty)); let llptrty = type_of::type_of(ccx, fn_ptr_ty); let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) { + // This is subtle and surprising, but sometimes we have to bitcast + // the resulting fn pointer. The reason has to do with external + // functions. If you have two crates that both bind the same C + // library, they may not use precisely the same types: for + // example, they will probably each declare their own structs, + // which are distinct types from LLVM's point of view (nominal + // types). + // + // Now, if those two crates are linked into an application, and + // they contain inlined code, you can wind up with a situation + // where both of those functions wind up being loaded into this + // application simultaneously. In that case, the same function + // (from LLVM's point of view) requires two types. But of course + // LLVM won't allow one function to have two types. + // + // What we currently do, therefore, is declare the function with + // one of the two types (whichever happens to come first) and then + // bitcast as needed when the function is referenced to make sure + // it has the type we expect. + // + // This can occur on either a crate-local or crate-external + // reference. It also occurs when testing libcore and in some + // other weird situations. Annoying. if common::val_ty(llfn) != llptrty { debug!("get_fn: casting {:?} to {:?}", llfn, llptrty); consts::ptrcast(llfn, llptrty) From 2eada5870615fafa1f40c4ce93f5f5adaf030cdf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 13 Sep 2017 15:24:13 -0700 Subject: [PATCH 09/11] rustc: Remove another global map from trans This commit removes the `crate_trans_items` field from the `CrateContext` of trans. This field, a big map, was calculated during partioning and was a set of all translation items. This isn't quite incremental-friendly because the map may change a lot but not have much effect on downstream consumers. Instead a new query was added for the one location this map was needed, along with a new comment explaining what the location is doing! --- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/ty/maps.rs | 5 ++-- src/librustc_trans/base.rs | 48 +++++++++++++++++++++--------- src/librustc_trans/callee.rs | 36 ++++++++++++++++++++-- src/librustc_trans/context.rs | 14 ++------- src/librustc_trans/lib.rs | 3 +- 6 files changed, 76 insertions(+), 31 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index bfbf280d6ddba..e3a9e96986432 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -579,6 +579,7 @@ define_dep_nodes!( <'tcx> [] CollectAndPartitionTranslationItems, [] ExportName(DefId), [] ContainsExternIndicator(DefId), + [] IsTranslatedFunction(DefId), ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index dd6d90503ef1b..307921a333507 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -24,7 +24,7 @@ use middle::resolve_lifetime::{Region, ObjectLifetimeDefault}; use middle::stability::{self, DeprecationEntry}; use middle::lang_items::{LanguageItems, LangItem}; use middle::exported_symbols::SymbolExportLevel; -use middle::trans::{TransItem, CodegenUnit}; +use middle::trans::CodegenUnit; use mir; use mir::transform::{MirSuite, MirPassIndex}; use session::CompileResult; @@ -1391,9 +1391,10 @@ define_maps! { <'tcx> -> Arc>, [] fn collect_and_partition_translation_items: collect_and_partition_translation_items_node(CrateNum) - -> (Arc>>, Vec>>), + -> (Arc, Arc>>>), [] fn export_name: ExportName(DefId) -> Option, [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool, + [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool, } fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 7941134cc7b07..f60f069f4eaef 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -35,7 +35,7 @@ use back::write::{self, OngoingCrateTranslation}; use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; use llvm; use metadata; -use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::middle::lang_items::StartFnLangItem; use rustc::middle::trans::{Linkage, Visibility}; use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes}; @@ -75,7 +75,7 @@ use trans_item::{TransItem, TransItemExt, DefPathBasedNames}; use type_::Type; use type_of; use value::Value; -use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet}; +use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet, DefIdSet}; use CrateInfo; use libc::c_uint; @@ -990,8 +990,9 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Run the translation item collector and partition the collected items into // codegen units. - let (translation_items, codegen_units) = - shared_ccx.tcx().collect_and_partition_translation_items(LOCAL_CRATE); + let codegen_units = + shared_ccx.tcx().collect_and_partition_translation_items(LOCAL_CRATE).1; + let codegen_units = (*codegen_units).clone(); assert!(codegen_units.len() <= 1 || !tcx.sess.lto()); @@ -1076,8 +1077,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let ((stats, module), _) = tcx.dep_graph.with_task(dep_node, AssertDepGraphSafe(&shared_ccx), - AssertDepGraphSafe((cgu, - translation_items.clone())), + AssertDepGraphSafe(cgu), module_translation); all_stats.extend(stats); @@ -1118,13 +1118,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn module_translation<'a, 'tcx>( scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, - args: AssertDepGraphSafe<(Arc>, - Arc>>)>) + args: AssertDepGraphSafe>>) -> (Stats, ModuleTranslation) { // FIXME(#40304): We ought to be using the id as a key and some queries, I think. let AssertDepGraphSafe(scx) = scx; - let AssertDepGraphSafe((cgu, crate_trans_items)) = args; + let AssertDepGraphSafe(cgu) = args; let cgu_name = cgu.name().to_string(); let cgu_id = cgu.work_product_id(); @@ -1164,7 +1163,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Instantiate translation items without filling out definitions yet... - let lcx = LocalCrateContext::new(scx, cgu, crate_trans_items); + let lcx = LocalCrateContext::new(scx, cgu); let module = { let ccx = CrateContext::new(scx, &lcx); let trans_items = ccx.codegen_unit() @@ -1353,7 +1352,7 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_i fn collect_and_partition_translation_items<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum, -) -> (Arc>>, Vec>>) +) -> (Arc, Arc>>>) { assert_eq!(cnum, LOCAL_CRATE); let time_passes = tcx.sess.time_passes(); @@ -1404,7 +1403,12 @@ fn collect_and_partition_translation_items<'a, 'tcx>( assert!(tcx.sess.opts.cg.codegen_units == codegen_units.len() || tcx.sess.opts.debugging_opts.incremental.is_some()); - let translation_items: FxHashSet> = items.iter().cloned().collect(); + let translation_items: DefIdSet = items.iter().filter_map(|trans_item| { + match *trans_item { + TransItem::Fn(ref instance) => Some(instance.def_id()), + _ => None, + } + }).collect(); if tcx.sess.opts.debugging_opts.print_trans_items.is_some() { let mut item_to_cgus = FxHashMap(); @@ -1459,7 +1463,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( } } - (Arc::new(translation_items), codegen_units) + (Arc::new(translation_items), Arc::new(codegen_units)) } impl CrateInfo { @@ -1505,9 +1509,25 @@ impl CrateInfo { } } -pub fn provide(providers: &mut Providers) { +fn is_translated_function(tcx: TyCtxt, id: DefId) -> bool { + // FIXME(#42293) needs red/green tracking to avoid failing a bunch of + // existing tests + tcx.dep_graph.with_ignore(|| { + let (all_trans_items, _) = + tcx.collect_and_partition_translation_items(LOCAL_CRATE); + all_trans_items.contains(&id) + }) +} + +pub fn provide_local(providers: &mut Providers) { providers.collect_and_partition_translation_items = collect_and_partition_translation_items; + + providers.is_translated_function = is_translated_function; +} + +pub fn provide_extern(providers: &mut Providers) { + providers.is_translated_function = is_translated_function; } pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index b62d60db23a98..52e6dce24ed92 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -23,7 +23,6 @@ use monomorphize::{self, Instance}; use rustc::hir::def_id::DefId; use rustc::ty::TypeFoldable; use rustc::ty::subst::Substs; -use trans_item::TransItem; use type_of; /// Translates a reference to a fn/method item, monomorphizing and @@ -109,10 +108,43 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attributes::unwind(llfn, true); } + // Apply an appropriate linkage/visibility value to our item that we + // just declared. + // + // This is sort of subtle. Inside our codegen unit we started off + // compilation by predefining all our own `TransItem` instances. That + // is, everything we're translating ourselves is already defined. That + // means that anything we're actually translating ourselves will have + // hit the above branch in `get_declared_value`. As a result, we're + // guaranteed here that we're declaring a symbol that won't get defined, + // or in other words we're referencing a foreign value. + // + // So because this is a foreign value we blanket apply an external + // linkage directive because it's coming from a different object file. + // The visibility here is where it gets tricky. This symbol could be + // referencing some foreign crate or foreign library (an `extern` + // block) in which case we want to leave the default visibility. We may + // also, though, have multiple codegen units. + // + // In the situation of multiple codegen units this function may be + // referencing a function from another codegen unit. If we're + // indeed referencing a symbol in another codegen unit then we're in one + // of two cases: + // + // * This is a symbol defined in a foreign crate and we're just + // monomorphizing in another codegen unit. In this case this symbols + // is for sure not exported, so both codegen units will be using + // hidden visibility. Hence, we apply a hidden visibility here. + // + // * This is a symbol defined in our local crate. If the symbol in the + // other codegen unit is also not exported then like with the foreign + // case we apply a hidden visibility. If the symbol is exported from + // the foreign object file, however, then we leave this at the + // default visibility as we'll just import it naturally. unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - if ccx.crate_trans_items().contains(&TransItem::Fn(instance)) { + if ccx.tcx().is_translated_function(instance_def_id) { if instance_def_id.is_local() { if !ccx.tcx().is_exported_symbol(instance_def_id) { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 62dadce76f0e7..a1666fa523195 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -22,14 +22,13 @@ use declare; use monomorphize::Instance; use partitioning::CodegenUnit; -use trans_item::TransItem; use type_::Type; use rustc_data_structures::base_n; use rustc::session::config::{self, NoDebugInfo, OutputFilenames}; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout}; -use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc::util::nodemap::FxHashMap; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -94,9 +93,6 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> { stats: Stats, codegen_unit: Arc>, - /// The translation items of the whole crate. - crate_trans_items: Arc>>, - /// Cache instances of monomorphic and polymorphic items instances: RefCell, ValueRef>>, /// Cache generated vtables @@ -349,8 +345,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { pub fn new(shared: &SharedCrateContext<'a, 'tcx>, - codegen_unit: Arc>, - crate_trans_items: Arc>>) + codegen_unit: Arc>) -> LocalCrateContext<'a, 'tcx> { unsafe { // Append ".rs" to LLVM module identifier. @@ -382,7 +377,6 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { llcx, stats: Stats::default(), codegen_unit, - crate_trans_items, instances: RefCell::new(FxHashMap()), vtables: RefCell::new(FxHashMap()), const_cstr_cache: RefCell::new(FxHashMap()), @@ -489,10 +483,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().codegen_unit } - pub fn crate_trans_items(&self) -> &FxHashSet> { - &self.local().crate_trans_items - } - pub fn td(&self) -> llvm::TargetDataRef { unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index d06c769458a74..4cbc98d26ded6 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -251,10 +251,11 @@ __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } pub fn provide_local(providers: &mut Providers) { back::symbol_names::provide(providers); back::symbol_export::provide_local(providers); - base::provide(providers); + base::provide_local(providers); } pub fn provide_extern(providers: &mut Providers) { back::symbol_names::provide(providers); back::symbol_export::provide_extern(providers); + base::provide_extern(providers); } From 3021c1d0bf45d7628f6bf75aefce952ddf26193d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 13 Sep 2017 16:03:24 -0700 Subject: [PATCH 10/11] rustc: Attach an mpsc channel to TyCtxt This commit attaches a channel to the LLVM workers to the `TyCtxt` which will later be used during the codegen query to actually send work to LLVM workers. Otherwise this commit is just plumbing this channel throughout the compiler to ensure it reaches the right consumers. --- src/librustc/ty/context.rs | 11 +++++++++++ src/librustc_driver/driver.rs | 21 +++++++++++++++------ src/librustc_trans/back/write.rs | 32 +++++++++++++++++--------------- src/librustc_trans/base.rs | 9 +++++++-- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fb0cdab0b6a0f..e932c9728db3e 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -64,6 +64,7 @@ use std::mem; use std::ops::Deref; use std::iter; use std::rc::Rc; +use std::sync::mpsc; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; @@ -901,6 +902,14 @@ pub struct GlobalCtxt<'tcx> { /// error reporting, and so is lazily initialized and generally /// shouldn't taint the common path (hence the RefCell). pub all_traits: RefCell>>, + + /// A general purpose channel to throw data out the back towards LLVM worker + /// threads. + /// + /// This is intended to only get used during the trans phase of the compiler + /// when satisfying the query for a particular codegen unit. Internally in + /// the query it'll send data along this channel to get processed later. + pub tx_to_llvm_workers: mpsc::Sender>, } impl<'tcx> GlobalCtxt<'tcx> { @@ -1025,6 +1034,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { named_region_map: resolve_lifetime::NamedRegionMap, hir: hir_map::Map<'tcx>, crate_name: &str, + tx: mpsc::Sender>, f: F) -> R where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R { @@ -1145,6 +1155,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { derive_macros: RefCell::new(NodeMap()), stability_interner: RefCell::new(FxHashSet()), all_traits: RefCell::new(None), + tx_to_llvm_workers: tx, }, f) } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9f7cb06488dde..0adcfa79039d6 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -46,6 +46,7 @@ use super::Compilation; use serialize::json; +use std::any::Any; use std::env; use std::ffi::{OsString, OsStr}; use std::fs; @@ -53,6 +54,7 @@ use std::io::{self, Write}; use std::iter; use std::path::{Path, PathBuf}; use std::rc::Rc; +use std::sync::mpsc; use syntax::{ast, diagnostics, visit}; use syntax::attr; use syntax::ext::base::ExtCtxt; @@ -214,7 +216,7 @@ pub fn compile_input(sess: &Session, &arena, &arenas, &crate_name, - |tcx, analysis, incremental_hashes_map, result| { + |tcx, analysis, incremental_hashes_map, rx, result| { { // Eventually, we will want to track plugins. let _ignore = tcx.dep_graph.in_ignore(); @@ -242,7 +244,9 @@ pub fn compile_input(sess: &Session, tcx.print_debug_stats(); } - let trans = phase_4_translate_to_llvm(tcx, incremental_hashes_map, + let trans = phase_4_translate_to_llvm(tcx, + incremental_hashes_map, + rx, &outputs); if log_enabled!(::log::LogLevel::Info) { @@ -914,6 +918,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>, ty::CrateAnalysis, IncrementalHashesMap, + mpsc::Receiver>, CompileResult) -> R { macro_rules! try_with_f { @@ -1028,6 +1033,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges); passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans")); + let (tx, rx) = mpsc::channel(); + TyCtxt::create_and_enter(sess, cstore, local_providers, @@ -1039,6 +1046,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, named_region_map, hir_map, name, + tx, |tcx| { let incremental_hashes_map = time(time_passes, @@ -1109,7 +1117,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "lint checking", || lint::check_crate(tcx)); - return Ok(f(tcx, analysis, incremental_hashes_map, tcx.sess.compile_status())); + return Ok(f(tcx, analysis, incremental_hashes_map, rx, tcx.sess.compile_status())); }) } @@ -1117,6 +1125,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, /// be discarded. pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: IncrementalHashesMap, + rx: mpsc::Receiver>, output_filenames: &OutputFilenames) -> write::OngoingCrateTranslation { let time_passes = tcx.sess.time_passes(); @@ -1126,9 +1135,9 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, || ::rustc::middle::dependency_format::calculate(tcx)); let translation = - time(time_passes, - "translation", - move || trans::trans_crate(tcx, incremental_hashes_map, output_filenames)); + time(time_passes, "translation", move || { + trans::trans_crate(tcx, incremental_hashes_map, rx, output_filenames) + }); if tcx.sess.profile_queries() { profile::dump("profile_queries".to_string()) diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index c8925ceb478ce..2535583cc6fbb 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -39,6 +39,7 @@ use context::{is_pie_binary, get_reloc_model}; use jobserver::{Client, Acquired}; use rustc_demangle; +use std::any::Any; use std::ffi::CString; use std::fmt; use std::fs; @@ -348,7 +349,7 @@ pub struct CodegenContext { // compiling incrementally pub incr_comp_session_dir: Option, // Channel back to the main control thread to send messages to - coordinator_send: Sender, + coordinator_send: Sender>, // A reference to the TimeGraph so we can register timings. None means that // measuring is disabled. time_graph: Option, @@ -674,7 +675,8 @@ pub fn start_async_translation(tcx: TyCtxt, crate_output: &OutputFilenames, time_graph: Option, link: LinkMeta, - metadata: EncodedMetadata) + metadata: EncodedMetadata, + coordinator_receive: Receiver>) -> OngoingCrateTranslation { let sess = tcx.sess; let crate_name = tcx.crate_name(LOCAL_CRATE); @@ -798,13 +800,12 @@ pub fn start_async_translation(tcx: TyCtxt, let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); let (trans_worker_send, trans_worker_receive) = channel(); - let (coordinator_send, coordinator_receive) = channel(); let coordinator_thread = start_executing_work(sess, &crate_info, shared_emitter, trans_worker_send, - coordinator_send.clone(), + tcx.tx_to_llvm_workers.clone(), coordinator_receive, client, time_graph.clone(), @@ -824,7 +825,7 @@ pub fn start_async_translation(tcx: TyCtxt, time_graph, output_filenames: crate_output.clone(), - coordinator_send, + coordinator_send: tcx.tx_to_llvm_workers.clone(), trans_worker_receive, shared_emitter_main, future: coordinator_thread @@ -1138,8 +1139,8 @@ fn start_executing_work(sess: &Session, crate_info: &CrateInfo, shared_emitter: SharedEmitter, trans_worker_send: Sender, - coordinator_send: Sender, - coordinator_receive: Receiver, + coordinator_send: Sender>, + coordinator_receive: Receiver>, jobserver: Client, time_graph: Option, exported_symbols: Arc) @@ -1156,7 +1157,7 @@ fn start_executing_work(sess: &Session, // tokens on `rx` above which will get managed in the main loop below. let coordinator_send2 = coordinator_send.clone(); let helper = jobserver.into_helper_thread(move |token| { - drop(coordinator_send2.send(Message::Token(token))); + drop(coordinator_send2.send(Box::new(Message::Token(token)))); }).expect("failed to spawn helper thread"); let mut each_linked_rlib_for_lto = Vec::new(); @@ -1430,7 +1431,8 @@ fn start_executing_work(sess: &Session, // Relinquish accidentally acquired extra tokens tokens.truncate(running); - match coordinator_receive.recv().unwrap() { + let msg = coordinator_receive.recv().unwrap(); + match *msg.downcast::().ok().unwrap() { // Save the token locally and the next turn of the loop will use // this to spawn a new unit of work, or it may get dropped // immediately if we have no more work to spawn. @@ -1588,7 +1590,7 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) { // Set up a destructor which will fire off a message that we're done as // we exit. struct Bomb { - coordinator_send: Sender, + coordinator_send: Sender>, result: Option, worker_id: usize, } @@ -1599,10 +1601,10 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) { None => Err(()) }; - drop(self.coordinator_send.send(Message::Done { + drop(self.coordinator_send.send(Box::new(Message::Done { result, worker_id: self.worker_id, - })); + }))); } } @@ -1845,7 +1847,7 @@ pub struct OngoingCrateTranslation { allocator_module_config: ModuleConfig, time_graph: Option, - coordinator_send: Sender, + coordinator_send: Sender>, trans_worker_receive: Receiver, shared_emitter_main: SharedEmitterMain, future: thread::JoinHandle, @@ -1931,11 +1933,11 @@ impl OngoingCrateTranslation { module_config, self.output_filenames.clone()); - drop(self.coordinator_send.send(Message::TranslationDone { + drop(self.coordinator_send.send(Box::new(Message::TranslationDone { llvm_work_item, cost, is_last - })); + }))); } pub fn submit_pre_translated_module_to_llvm(&self, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f60f069f4eaef..1b802f7420132 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -79,11 +79,13 @@ use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet, DefIdSet}; use CrateInfo; use libc::c_uint; +use std::any::Any; use std::ffi::{CStr, CString}; use std::str; use std::sync::Arc; use std::time::{Instant, Duration}; use std::i32; +use std::sync::mpsc; use syntax_pos::Span; use syntax::attr; use rustc::hir; @@ -933,6 +935,7 @@ pub fn find_exported_symbols(tcx: TyCtxt) -> NodeSet { pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: IncrementalHashesMap, + rx: mpsc::Receiver>, output_filenames: &OutputFilenames) -> OngoingCrateTranslation { check_for_rustc_errors_attr(tcx); @@ -974,7 +977,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output_filenames, time_graph.clone(), link_meta, - metadata); + metadata, + rx); ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, metadata_module, true); @@ -1001,7 +1005,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output_filenames, time_graph.clone(), link_meta, - metadata); + metadata, + rx); // Translate an allocator shim, if any // From 6d614ddc2ebc25d3987b1efc84c0c7fea00ce325 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 13 Sep 2017 20:26:39 -0700 Subject: [PATCH 11/11] rustc: Move codegen to a query This commit moves the actual code generation in the compiler behind a query keyed by a codegen unit's name. This ended up entailing quite a few internal refactorings to enable this, along with a few cut corners: * The `OutputFilenames` structure is now tracked in the `TyCtxt` as it affects a whole bunch of trans and such. This is now behind a query and threaded into the construction of the `TyCtxt`. * The `TyCtxt` now has a channel "out the back" intended to send data to worker threads in rustc_trans. This is used as a sort of side effect of the codegen query but morally what's happening here is the return value of the query (currently unit but morally a path) is only valid once the background threads have all finished. * Dispatching work items to the codegen threads was refactored to only rely on data in `TyCtxt`, which mostly just involved refactoring where data was stored, moving it from the translation thread to the controller thread's `CodegenContext` or the like. * A new thread locals was introduced in trans to work around the query system. This is used in the implementation of `assert_module_sources` which looks like an artifact of the old query system and will presumably go away once red/green is up and running. --- src/librustc/dep_graph/dep_node.rs | 4 + src/librustc/middle/trans.rs | 31 ++ src/librustc/ty/context.rs | 10 + src/librustc/ty/maps.rs | 39 +- src/librustc_driver/driver.rs | 25 +- src/librustc_driver/lib.rs | 1 + src/librustc_driver/pretty.rs | 14 +- src/librustc_driver/test.rs | 14 + src/librustc_trans/back/write.rs | 248 ++++++------- src/librustc_trans/base.rs | 433 ++++++++++++----------- src/librustc_trans/builder.rs | 9 +- src/librustc_trans/context.rs | 58 +-- src/librustc_trans/debuginfo/metadata.rs | 4 +- src/librustc_trans/glue.rs | 3 +- src/librustc_trans/monomorphize.rs | 2 +- src/librustc_trans/partitioning.rs | 9 +- src/librustdoc/core.rs | 8 +- 17 files changed, 484 insertions(+), 428 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e3a9e96986432..06469c16bc22e 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -71,6 +71,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use ich::StableHashingContext; use std::fmt; use std::hash::Hash; +use syntax_pos::symbol::InternedString; // erase!() just makes tokens go away. It's used to specify which macro argument // is repeated (i.e. which sub-expression of the macro we are in) but don't need @@ -580,6 +581,9 @@ define_dep_nodes!( <'tcx> [] ExportName(DefId), [] ContainsExternIndicator(DefId), [] IsTranslatedFunction(DefId), + [] CodegenUnit(InternedString), + [] CompileCodegenUnit(InternedString), + [] OutputFilenames, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/middle/trans.rs b/src/librustc/middle/trans.rs index cf8e9cbbd3d31..9a50125754846 100644 --- a/src/librustc/middle/trans.rs +++ b/src/librustc/middle/trans.rs @@ -77,3 +77,34 @@ impl<'tcx> CodegenUnit<'tcx> { &mut self.items } } + +#[derive(Clone, Default)] +pub struct Stats { + pub n_glues_created: usize, + pub n_null_glues: usize, + pub n_real_glues: usize, + pub n_fns: usize, + pub n_inlines: usize, + pub n_closures: usize, + pub n_llvm_insns: usize, + pub llvm_insns: FxHashMap, + // (ident, llvm-instructions) + pub fn_stats: Vec<(String, usize)>, +} + +impl Stats { + pub fn extend(&mut self, stats: Stats) { + self.n_glues_created += stats.n_glues_created; + self.n_null_glues += stats.n_null_glues; + self.n_real_glues += stats.n_real_glues; + self.n_fns += stats.n_fns; + self.n_inlines += stats.n_inlines; + self.n_closures += stats.n_closures; + self.n_llvm_insns += stats.n_llvm_insns; + + for (k, v) in stats.llvm_insns { + *self.llvm_insns.entry(k).or_insert(0) += v; + } + self.fn_stats.extend(stats.fn_stats); + } +} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e932c9728db3e..945a081442750 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -13,6 +13,7 @@ use dep_graph::DepGraph; use errors::DiagnosticBuilder; use session::Session; +use session::config::OutputFilenames; use middle; use hir::{TraitCandidate, HirId, ItemLocalId}; use hir::def::{Def, Export}; @@ -65,6 +66,7 @@ use std::ops::Deref; use std::iter; use std::rc::Rc; use std::sync::mpsc; +use std::sync::Arc; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; @@ -910,6 +912,8 @@ pub struct GlobalCtxt<'tcx> { /// when satisfying the query for a particular codegen unit. Internally in /// the query it'll send data along this channel to get processed later. pub tx_to_llvm_workers: mpsc::Sender>, + + output_filenames: Arc, } impl<'tcx> GlobalCtxt<'tcx> { @@ -1035,6 +1039,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { hir: hir_map::Map<'tcx>, crate_name: &str, tx: mpsc::Sender>, + output_filenames: &OutputFilenames, f: F) -> R where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R { @@ -1156,6 +1161,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { stability_interner: RefCell::new(FxHashSet()), all_traits: RefCell::new(None), tx_to_llvm_workers: tx, + output_filenames: Arc::new(output_filenames.clone()), }, f) } @@ -2229,4 +2235,8 @@ pub fn provide(providers: &mut ty::maps::Providers) { assert_eq!(cnum, LOCAL_CRATE); Rc::new(tcx.cstore.postorder_cnums_untracked()) }; + providers.output_filenames = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + tcx.output_filenames.clone() + }; } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 307921a333507..bf17b82535cc1 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -24,10 +24,11 @@ use middle::resolve_lifetime::{Region, ObjectLifetimeDefault}; use middle::stability::{self, DeprecationEntry}; use middle::lang_items::{LanguageItems, LangItem}; use middle::exported_symbols::SymbolExportLevel; -use middle::trans::CodegenUnit; +use middle::trans::{CodegenUnit, Stats}; use mir; use mir::transform::{MirSuite, MirPassIndex}; use session::CompileResult; +use session::config::OutputFilenames; use traits::specialization_graph; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; use ty::layout::{Layout, LayoutError}; @@ -52,6 +53,7 @@ use std::ops::Deref; use std::rc::Rc; use std::sync::Arc; use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::symbol::InternedString; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; @@ -180,6 +182,15 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { } } +impl Key for InternedString { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } @@ -760,6 +771,24 @@ impl<'tcx> QueryDescription for queries::collect_and_partition_translation_items } } +impl<'tcx> QueryDescription for queries::codegen_unit<'tcx> { + fn describe(_tcx: TyCtxt, _: InternedString) -> String { + format!("codegen_unit") + } +} + +impl<'tcx> QueryDescription for queries::compile_codegen_unit<'tcx> { + fn describe(_tcx: TyCtxt, _: InternedString) -> String { + format!("compile_codegen_unit") + } +} + +impl<'tcx> QueryDescription for queries::output_filenames<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("output_filenames") + } +} + // If enabled, send a message to the profile-queries thread macro_rules! profq_msg { ($tcx:expr, $msg:expr) => { @@ -1395,6 +1424,10 @@ define_maps! { <'tcx> [] fn export_name: ExportName(DefId) -> Option, [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool, [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool, + [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, + [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, + [] fn output_filenames: output_filenames_node(CrateNum) + -> Arc, } fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { @@ -1512,3 +1545,7 @@ fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::CollectAndPartitionTranslationItems } + +fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::OutputFilenames +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 0adcfa79039d6..32a160bcffcef 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -193,6 +193,7 @@ pub fn compile_input(sess: &Session, &resolutions, &expanded_crate, &hir_map.krate(), + &outputs, &crate_name), Ok(())); } @@ -216,6 +217,7 @@ pub fn compile_input(sess: &Session, &arena, &arenas, &crate_name, + &outputs, |tcx, analysis, incremental_hashes_map, rx, result| { { // Eventually, we will want to track plugins. @@ -246,8 +248,7 @@ pub fn compile_input(sess: &Session, let trans = phase_4_translate_to_llvm(tcx, incremental_hashes_map, - rx, - &outputs); + rx); if log_enabled!(::log::LogLevel::Info) { println!("Post-trans"); @@ -261,7 +262,7 @@ pub fn compile_input(sess: &Session, } } - Ok((outputs, trans, tcx.dep_graph.clone())) + Ok((outputs.clone(), trans, tcx.dep_graph.clone())) })?? }; @@ -486,6 +487,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { resolutions: &'a Resolutions, krate: &'a ast::Crate, hir_crate: &'a hir::Crate, + output_filenames: &'a OutputFilenames, crate_name: &'a str) -> Self { CompileState { @@ -498,6 +500,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { resolutions: Some(resolutions), expanded_crate: Some(krate), hir_crate: Some(hir_crate), + output_filenames: Some(output_filenames), out_file: out_file.as_ref().map(|s| &**s), ..CompileState::empty(input, session, out_dir) } @@ -913,6 +916,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, arena: &'tcx DroplessArena, arenas: &'tcx GlobalArenas<'tcx>, name: &str, + output_filenames: &OutputFilenames, f: F) -> Result where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>, @@ -922,11 +926,11 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, CompileResult) -> R { macro_rules! try_with_f { - ($e: expr, ($t: expr, $a: expr, $h: expr)) => { + ($e: expr, ($($t:tt)*)) => { match $e { Ok(x) => x, Err(x) => { - f($t, $a, $h, Err(x)); + f($($t)*, Err(x)); return Err(x); } } @@ -1047,6 +1051,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, hir_map, name, tx, + output_filenames, |tcx| { let incremental_hashes_map = time(time_passes, @@ -1062,7 +1067,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, || stability::check_unstable_api_usage(tcx)); // passes are timed inside typeck - try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map)); + try_with_f!(typeck::check_crate(tcx), + (tcx, analysis, incremental_hashes_map, rx)); time(time_passes, "const checking", @@ -1106,7 +1112,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis if sess.err_count() > 0 { - return Ok(f(tcx, analysis, incremental_hashes_map, sess.compile_status())); + return Ok(f(tcx, analysis, incremental_hashes_map, rx, sess.compile_status())); } time(time_passes, "death checking", || middle::dead::check_crate(tcx)); @@ -1125,8 +1131,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, /// be discarded. pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: IncrementalHashesMap, - rx: mpsc::Receiver>, - output_filenames: &OutputFilenames) + rx: mpsc::Receiver>) -> write::OngoingCrateTranslation { let time_passes = tcx.sess.time_passes(); @@ -1136,7 +1141,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let translation = time(time_passes, "translation", move || { - trans::trans_crate(tcx, incremental_hashes_map, rx, output_filenames) + trans::trans_crate(tcx, incremental_hashes_map, rx) }); if tcx.sess.profile_queries() { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 522b9eb22320e..044f4a5eaf512 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -645,6 +645,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { ppm, state.arena.unwrap(), state.arenas.unwrap(), + state.output_filenames.unwrap(), opt_uii.clone(), state.out_file); }; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 82dda2d2aa162..cd153b820776e 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -23,7 +23,7 @@ use rustc::cfg::graphviz::LabelledCFG; use rustc::dep_graph::DepGraph; use rustc::middle::cstore::CrateStore; use rustc::session::Session; -use rustc::session::config::Input; +use rustc::session::config::{Input, OutputFilenames}; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; @@ -205,6 +205,7 @@ impl PpSourceMode { resolutions: &Resolutions, arena: &'tcx DroplessArena, arenas: &'tcx GlobalArenas<'tcx>, + output_filenames: &OutputFilenames, id: &str, f: F) -> A @@ -235,7 +236,8 @@ impl PpSourceMode { arena, arenas, id, - |tcx, _, _, _| { + output_filenames, + |tcx, _, _, _, _| { let empty_tables = ty::TypeckTables::empty(None); let annotation = TypedAnnotation { tcx, @@ -888,6 +890,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, ppm: PpMode, arena: &'tcx DroplessArena, arenas: &'tcx GlobalArenas<'tcx>, + output_filenames: &OutputFilenames, opt_uii: Option, ofile: Option<&Path>) { let dep_graph = DepGraph::new(false); @@ -902,6 +905,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, crate_name, arena, arenas, + output_filenames, ppm, opt_uii, ofile); @@ -940,6 +944,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, resolutions, arena, arenas, + output_filenames, crate_name, move |annotation, krate| { debug!("pretty printing source code {:?}", s); @@ -964,6 +969,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, resolutions, arena, arenas, + output_filenames, crate_name, move |annotation, _| { debug!("pretty printing source code {:?}", s); @@ -1007,6 +1013,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, crate_name: &str, arena: &'tcx DroplessArena, arenas: &'tcx GlobalArenas<'tcx>, + output_filenames: &OutputFilenames, ppm: PpMode, uii: Option, ofile: Option<&Path>) { @@ -1028,7 +1035,8 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, arena, arenas, crate_name, - |tcx, _, _, _| { + output_filenames, + |tcx, _, _, _, _| { match ppm { PpmMir | PpmMirCFG => { if let Some(nodeid) = nodeid { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index d0edcbc326098..34f4e0e7b0c95 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -10,6 +10,9 @@ //! # Standalone Tests for the Inference Module +use std::path::PathBuf; +use std::sync::mpsc; + use driver; use rustc_lint; use rustc_resolve::MakeGlobMap; @@ -26,6 +29,7 @@ use rustc_metadata::cstore::CStore; use rustc::hir::map as hir_map; use rustc::mir::transform::Passes; use rustc::session::{self, config}; +use rustc::session::config::{OutputFilenames, OutputTypes}; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; @@ -133,6 +137,14 @@ fn test_env(source_string: &str, // run just enough stuff to build a tcx: let named_region_map = resolve_lifetime::krate(&sess, &*cstore, &hir_map); + let (tx, _rx) = mpsc::channel(); + let outputs = OutputFilenames { + out_directory: PathBuf::new(), + out_filestem: String::new(), + single_output_file: None, + extra: String::new(), + outputs: OutputTypes::new(&[]), + }; TyCtxt::create_and_enter(&sess, &*cstore, ty::maps::Providers::default(), @@ -144,6 +156,8 @@ fn test_env(source_string: &str, named_region_map.unwrap(), hir_map, "test_crate", + tx, + &outputs, |tcx| { tcx.infer_ctxt().enter(|infcx| { let mut region_scope_tree = region::ScopeTree::default(); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 2535583cc6fbb..ef6bf2504f312 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -203,8 +203,6 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef { /// Module-specific configuration for `optimize_and_codegen`. pub struct ModuleConfig { - /// LLVM TargetMachine to use for codegen. - tm: TargetMachineRef, /// Names of additional optimization passes to run. passes: Vec, /// Some(level) to optimize at a certain level, or None to run @@ -237,12 +235,9 @@ pub struct ModuleConfig { obj_is_bitcode: bool, } -unsafe impl Send for ModuleConfig { } - impl ModuleConfig { - fn new(sess: &Session, passes: Vec) -> ModuleConfig { + fn new(passes: Vec) -> ModuleConfig { ModuleConfig { - tm: create_target_machine(sess), passes, opt_level: None, opt_size: None, @@ -290,40 +285,6 @@ impl ModuleConfig { self.merge_functions = sess.opts.optimize == config::OptLevel::Default || sess.opts.optimize == config::OptLevel::Aggressive; } - - fn clone(&self, sess: &Session) -> ModuleConfig { - ModuleConfig { - tm: create_target_machine(sess), - passes: self.passes.clone(), - opt_level: self.opt_level, - opt_size: self.opt_size, - - emit_no_opt_bc: self.emit_no_opt_bc, - emit_bc: self.emit_bc, - emit_lto_bc: self.emit_lto_bc, - emit_ir: self.emit_ir, - emit_asm: self.emit_asm, - emit_obj: self.emit_obj, - obj_is_bitcode: self.obj_is_bitcode, - - no_verify: self.no_verify, - no_prepopulate_passes: self.no_prepopulate_passes, - no_builtins: self.no_builtins, - time_passes: self.time_passes, - vectorize_loop: self.vectorize_loop, - vectorize_slp: self.vectorize_slp, - merge_functions: self.merge_functions, - inline_threshold: self.inline_threshold, - } - } -} - -impl Drop for ModuleConfig { - fn drop(&mut self) { - unsafe { - llvm::LLVMRustDisposeTargetMachine(self.tm); - } - } } /// Additional resources used by optimize_and_codegen (not module specific) @@ -337,6 +298,11 @@ pub struct CodegenContext { pub opts: Arc, pub crate_types: Vec, pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>, + output_filenames: Arc, + regular_module_config: Arc, + metadata_module_config: Arc, + allocator_module_config: Arc, + // Handler to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, // LLVM passes added by plugins. @@ -359,6 +325,14 @@ impl CodegenContext { fn create_diag_handler(&self) -> Handler { Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone())) } + + fn config(&self, kind: ModuleKind) -> &ModuleConfig { + match kind { + ModuleKind::Regular => &self.regular_module_config, + ModuleKind::Metadata => &self.metadata_module_config, + ModuleKind::Allocator => &self.allocator_module_config, + } + } } struct HandlerFreeVars<'a> { @@ -418,8 +392,8 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo unsafe fn optimize_and_codegen(cgcx: &CodegenContext, diag_handler: &Handler, mtrans: ModuleTranslation, - config: ModuleConfig, - output_names: OutputFilenames) + tm: TargetMachineRef, + config: &ModuleConfig) -> Result { let (llmod, llcx) = match mtrans.source { @@ -429,8 +403,6 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } }; - let tm = config.tm; - let fv = HandlerFreeVars { cgcx, diag_handler, @@ -444,7 +416,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let module_name = Some(&module_name[..]); if config.emit_no_opt_bc { - let out = output_names.temp_path_ext("no-opt.bc", module_name); + let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); let out = path2cstr(&out); llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } @@ -517,7 +489,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if cgcx.lto { time(cgcx.time_passes, "all lto passes", || { let temp_no_opt_bc_filename = - output_names.temp_path_ext("no-opt.lto.bc", module_name); + cgcx.output_filenames.temp_path_ext("no-opt.lto.bc", module_name); lto::run(cgcx, diag_handler, llmod, @@ -526,7 +498,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, &temp_no_opt_bc_filename) })?; if config.emit_lto_bc { - let out = output_names.temp_path_ext("lto.bc", module_name); + let out = cgcx.output_filenames.temp_path_ext("lto.bc", module_name); let out = path2cstr(&out); llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } @@ -562,8 +534,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let write_obj = config.emit_obj && !config.obj_is_bitcode; let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; - let bc_out = output_names.temp_path(OutputType::Bitcode, module_name); - let obj_out = output_names.temp_path(OutputType::Object, module_name); + let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); + let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); if write_bc { let bc_out_c = path2cstr(&bc_out); @@ -573,7 +545,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()), || -> Result<(), FatalError> { if config.emit_ir { - let out = output_names.temp_path(OutputType::LlvmAssembly, module_name); + let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); let out = path2cstr(&out); extern "C" fn demangle_callback(input_ptr: *const c_char, @@ -614,7 +586,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } if config.emit_asm { - let path = output_names.temp_path(OutputType::Assembly, module_name); + let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); // We can't use the same module for asm and binary output, because that triggers // various errors like invalid IR or broken binaries, so we might have to clone the @@ -672,13 +644,13 @@ fn need_crate_bitcode_for_rlib(sess: &Session) -> bool { } pub fn start_async_translation(tcx: TyCtxt, - crate_output: &OutputFilenames, time_graph: Option, link: LinkMeta, metadata: EncodedMetadata, coordinator_receive: Receiver>) -> OngoingCrateTranslation { let sess = tcx.sess; + let crate_output = tcx.output_filenames(LOCAL_CRATE); let crate_name = tcx.crate_name(LOCAL_CRATE); let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins"); let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs, @@ -699,13 +671,6 @@ pub fn start_async_translation(tcx: TyCtxt, let linker_info = LinkerInfo::new(tcx); let crate_info = CrateInfo::new(tcx); - let mut exported_symbols = FxHashMap(); - exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE)); - for &cnum in tcx.crates().iter() { - exported_symbols.insert(cnum, tcx.exported_symbols(cnum)); - } - let exported_symbols = Arc::new(exported_symbols); - let output_types_override = if no_integrated_as { OutputTypes::new(&[(OutputType::Assembly, None)]) } else { @@ -713,9 +678,9 @@ pub fn start_async_translation(tcx: TyCtxt, }; // Figure out what we actually need to build. - let mut modules_config = ModuleConfig::new(sess, sess.opts.cg.passes.clone()); - let mut metadata_config = ModuleConfig::new(sess, vec![]); - let mut allocator_config = ModuleConfig::new(sess, vec![]); + let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone()); + let mut metadata_config = ModuleConfig::new(vec![]); + let mut allocator_config = ModuleConfig::new(vec![]); if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer { match *sanitizer { @@ -801,15 +766,17 @@ pub fn start_async_translation(tcx: TyCtxt, let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); let (trans_worker_send, trans_worker_receive) = channel(); - let coordinator_thread = start_executing_work(sess, + let coordinator_thread = start_executing_work(tcx, &crate_info, shared_emitter, trans_worker_send, - tcx.tx_to_llvm_workers.clone(), coordinator_receive, client, time_graph.clone(), - exported_symbols.clone()); + Arc::new(modules_config), + Arc::new(metadata_config), + Arc::new(allocator_config)); + OngoingCrateTranslation { crate_name, link, @@ -819,16 +786,12 @@ pub fn start_async_translation(tcx: TyCtxt, no_integrated_as, crate_info, - regular_module_config: modules_config, - metadata_module_config: metadata_config, - allocator_module_config: allocator_config, - time_graph, - output_filenames: crate_output.clone(), coordinator_send: tcx.tx_to_llvm_workers.clone(), trans_worker_receive, shared_emitter_main, - future: coordinator_thread + future: coordinator_thread, + output_filenames: tcx.output_filenames(LOCAL_CRATE), } } @@ -1029,8 +992,7 @@ pub fn dump_incremental_data(trans: &CrateTranslation) { struct WorkItem { mtrans: ModuleTranslation, - config: ModuleConfig, - output_names: OutputFilenames + tm: TargetMachine, } impl fmt::Debug for WorkItem { @@ -1039,15 +1001,15 @@ impl fmt::Debug for WorkItem { } } -fn build_work_item(mtrans: ModuleTranslation, - config: ModuleConfig, - output_names: OutputFilenames) - -> WorkItem -{ - WorkItem { - mtrans, - config, - output_names, +struct TargetMachine(TargetMachineRef); + +unsafe impl Send for TargetMachine {} + +impl Drop for TargetMachine { + fn drop(&mut self) { + unsafe { + llvm::LLVMRustDisposeTargetMachine(self.0); + } } } @@ -1056,6 +1018,7 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) { let diag_handler = cgcx.create_diag_handler(); let module_name = work_item.mtrans.name.clone(); + let config = cgcx.config(work_item.mtrans.kind); let pre_existing = match work_item.mtrans.source { ModuleSource::Translated(_) => None, @@ -1068,7 +1031,7 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) .unwrap(); let name = &work_item.mtrans.name; for (kind, saved_file) in wp.saved_files { - let obj_out = work_item.output_names.temp_path(kind, Some(name)); + let obj_out = cgcx.output_filenames.temp_path(kind, Some(name)); let source_file = in_incr_comp_dir(&incr_comp_session_dir, &saved_file); debug!("copying pre-existing module `{}` from {:?} to {}", @@ -1091,8 +1054,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) kind: ModuleKind::Regular, pre_existing: true, symbol_name_hash: work_item.mtrans.symbol_name_hash, - emit_bc: work_item.config.emit_bc, - emit_obj: work_item.config.emit_obj, + emit_bc: config.emit_bc, + emit_obj: config.emit_obj, }) } else { debug!("llvm-optimizing {:?}", module_name); @@ -1101,8 +1064,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) optimize_and_codegen(cgcx, &diag_handler, work_item.mtrans, - work_item.config, - work_item.output_names) + work_item.tm.0, + config) } } } @@ -1117,8 +1080,8 @@ enum Message { TranslationDone { llvm_work_item: WorkItem, cost: u64, - is_last: bool, }, + TranslationComplete, TranslateItem, } @@ -1135,16 +1098,26 @@ enum MainThreadWorkerState { LLVMing, } -fn start_executing_work(sess: &Session, +fn start_executing_work(tcx: TyCtxt, crate_info: &CrateInfo, shared_emitter: SharedEmitter, trans_worker_send: Sender, - coordinator_send: Sender>, coordinator_receive: Receiver>, jobserver: Client, time_graph: Option, - exported_symbols: Arc) + modules_config: Arc, + metadata_config: Arc, + allocator_config: Arc) -> thread::JoinHandle { + let coordinator_send = tcx.tx_to_llvm_workers.clone(); + let mut exported_symbols = FxHashMap(); + exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE)); + for &cnum in tcx.crates().iter() { + exported_symbols.insert(cnum, tcx.exported_symbols(cnum)); + } + let exported_symbols = Arc::new(exported_symbols); + let sess = tcx.sess; + // First up, convert our jobserver into a helper thread so we can use normal // mpsc channels to manage our messages and such. Once we've got the helper // thread then request `n-1` tokens because all of our work items are ready @@ -1183,6 +1156,10 @@ fn start_executing_work(sess: &Session, coordinator_send, diag_emitter: shared_emitter.clone(), time_graph, + output_filenames: tcx.output_filenames(LOCAL_CRATE), + regular_module_config: modules_config, + metadata_module_config: metadata_config, + allocator_module_config: allocator_config, }; // This is the "main loop" of parallel work happening for parallel codegen. @@ -1332,7 +1309,7 @@ fn start_executing_work(sess: &Session, let mut translation_done = false; // This is the queue of LLVM work items that still need processing. - let mut work_items = Vec::new(); + let mut work_items = Vec::<(WorkItem, u64)>::new(); // This are the Jobserver Tokens we currently hold. Does not include // the implicit Token the compiler process owns no matter what. @@ -1371,7 +1348,8 @@ fn start_executing_work(sess: &Session, worker: get_worker_id(&mut free_worker_ids), .. cgcx.clone() }; - maybe_start_llvm_timer(&item, &mut llvm_start_time); + maybe_start_llvm_timer(cgcx.config(item.mtrans.kind), + &mut llvm_start_time); main_thread_worker_state = MainThreadWorkerState::LLVMing; spawn_work(cgcx, item); } @@ -1387,7 +1365,8 @@ fn start_executing_work(sess: &Session, worker: get_worker_id(&mut free_worker_ids), .. cgcx.clone() }; - maybe_start_llvm_timer(&item, &mut llvm_start_time); + maybe_start_llvm_timer(cgcx.config(item.mtrans.kind), + &mut llvm_start_time); main_thread_worker_state = MainThreadWorkerState::LLVMing; spawn_work(cgcx, item); } else { @@ -1417,7 +1396,8 @@ fn start_executing_work(sess: &Session, while work_items.len() > 0 && running < tokens.len() { let (item, _) = work_items.pop().unwrap(); - maybe_start_llvm_timer(&item, &mut llvm_start_time); + maybe_start_llvm_timer(cgcx.config(item.mtrans.kind), + &mut llvm_start_time); let cgcx = CodegenContext { worker: get_worker_id(&mut free_worker_ids), @@ -1459,7 +1439,7 @@ fn start_executing_work(sess: &Session, } } - Message::TranslationDone { llvm_work_item, cost, is_last } => { + Message::TranslationDone { llvm_work_item, cost } => { // We keep the queue sorted by estimated processing cost, // so that more expensive items are processed earlier. This // is good for throughput as it gives the main thread more @@ -1475,15 +1455,14 @@ fn start_executing_work(sess: &Session, }; work_items.insert(insertion_index, (llvm_work_item, cost)); - if is_last { - // If this is the last, don't request a token because - // the trans worker thread will be free to handle this - // immediately. - translation_done = true; - } else { - helper.request_token(); - } + helper.request_token(); + assert_eq!(main_thread_worker_state, + MainThreadWorkerState::Translating); + main_thread_worker_state = MainThreadWorkerState::Idle; + } + Message::TranslationComplete => { + translation_done = true; assert_eq!(main_thread_worker_state, MainThreadWorkerState::Translating); main_thread_worker_state = MainThreadWorkerState::Idle; @@ -1561,11 +1540,11 @@ fn start_executing_work(sess: &Session, items_in_queue >= max_workers.saturating_sub(workers_running / 2) } - fn maybe_start_llvm_timer(work_item: &WorkItem, + fn maybe_start_llvm_timer(config: &ModuleConfig, llvm_start_time: &mut Option) { // We keep track of the -Ztime-passes output manually, // since the closure-based interface does not fit well here. - if work_item.config.time_passes { + if config.time_passes { if llvm_start_time.is_none() { *llvm_start_time = Some(Instant::now()); } @@ -1840,17 +1819,12 @@ pub struct OngoingCrateTranslation { linker_info: LinkerInfo, no_integrated_as: bool, crate_info: CrateInfo, - - output_filenames: OutputFilenames, - regular_module_config: ModuleConfig, - metadata_module_config: ModuleConfig, - allocator_module_config: ModuleConfig, - time_graph: Option, coordinator_send: Sender>, trans_worker_receive: Receiver, shared_emitter_main: SharedEmitterMain, future: thread::JoinHandle, + output_filenames: Arc, } impl OngoingCrateTranslation { @@ -1918,38 +1892,21 @@ impl OngoingCrateTranslation { trans } - pub fn submit_translated_module_to_llvm(&self, - sess: &Session, - mtrans: ModuleTranslation, - cost: u64, - is_last: bool) { - let module_config = match mtrans.kind { - ModuleKind::Regular => self.regular_module_config.clone(sess), - ModuleKind::Metadata => self.metadata_module_config.clone(sess), - ModuleKind::Allocator => self.allocator_module_config.clone(sess), - }; - - let llvm_work_item = build_work_item(mtrans, - module_config, - self.output_filenames.clone()); - - drop(self.coordinator_send.send(Box::new(Message::TranslationDone { - llvm_work_item, - cost, - is_last - }))); - } - pub fn submit_pre_translated_module_to_llvm(&self, - sess: &Session, - mtrans: ModuleTranslation, - is_last: bool) { + tcx: TyCtxt, + mtrans: ModuleTranslation) { self.wait_for_signal_to_translate_item(); - self.check_for_errors(sess); + self.check_for_errors(tcx.sess); // These are generally cheap and won't through off scheduling. let cost = 0; - self.submit_translated_module_to_llvm(sess, mtrans, cost, is_last); + submit_translated_module_to_llvm(tcx, mtrans, cost); + } + + pub fn translation_finished(&self, tcx: TyCtxt) { + self.wait_for_signal_to_translate_item(); + self.check_for_errors(tcx.sess); + drop(self.coordinator_send.send(Box::new(Message::TranslationComplete))); } pub fn check_for_errors(&self, sess: &Session) { @@ -1971,3 +1928,16 @@ impl OngoingCrateTranslation { } } } + +pub fn submit_translated_module_to_llvm(tcx: TyCtxt, + mtrans: ModuleTranslation, + cost: u64) { + let llvm_work_item = WorkItem { + mtrans, + tm: TargetMachine(create_target_machine(tcx.sess)), + }; + drop(tcx.tx_to_llvm_workers.send(Box::new(Message::TranslationDone { + llvm_work_item, + cost, + }))); +} diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 1b802f7420132..d86f88d4c7da0 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -28,7 +28,7 @@ use super::ModuleSource; use super::ModuleTranslation; use super::ModuleKind; -use assert_module_sources; +use assert_module_sources::{self, Disposition}; use back::link; use back::symbol_export; use back::write::{self, OngoingCrateTranslation}; @@ -37,7 +37,7 @@ use llvm; use metadata; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::middle::lang_items::StartFnLangItem; -use rustc::middle::trans::{Linkage, Visibility}; +use rustc::middle::trans::{Linkage, Visibility, Stats}; use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; @@ -45,7 +45,7 @@ use rustc::dep_graph::AssertDepGraphSafe; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; use rustc::hir::map as hir_map; use rustc::util::common::{time, print_time_passes_entry}; -use rustc::session::config::{self, NoDebugInfo, OutputFilenames}; +use rustc::session::config::{self, NoDebugInfo}; use rustc::session::Session; use rustc_incremental::{self, IncrementalHashesMap}; use abi; @@ -61,7 +61,7 @@ use common::CrateContext; use common::{type_is_zero_size, val_ty}; use common; use consts; -use context::{self, LocalCrateContext, SharedCrateContext, Stats}; +use context::{self, LocalCrateContext, SharedCrateContext}; use debuginfo; use declare; use machine; @@ -80,6 +80,7 @@ use CrateInfo; use libc::c_uint; use std::any::Any; +use std::cell::RefCell; use std::ffi::{CStr, CString}; use std::str; use std::sync::Arc; @@ -87,6 +88,7 @@ use std::time::{Instant, Duration}; use std::i32; use std::sync::mpsc; use syntax_pos::Span; +use syntax_pos::symbol::InternedString; use syntax::attr; use rustc::hir; use syntax::ast; @@ -101,7 +103,7 @@ pub struct StatRecorder<'a, 'tcx: 'a> { impl<'a, 'tcx> StatRecorder<'a, 'tcx> { pub fn new(ccx: &'a CrateContext<'a, 'tcx>, name: String) -> StatRecorder<'a, 'tcx> { - let istart = ccx.stats().n_llvm_insns.get(); + let istart = ccx.stats().borrow().n_llvm_insns; StatRecorder { ccx, name: Some(name), @@ -113,12 +115,12 @@ impl<'a, 'tcx> StatRecorder<'a, 'tcx> { impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { fn drop(&mut self) { if self.ccx.sess().trans_stats() { - let iend = self.ccx.stats().n_llvm_insns.get(); - self.ccx.stats().fn_stats.borrow_mut() - .push((self.name.take().unwrap(), iend - self.istart)); - self.ccx.stats().n_fns.set(self.ccx.stats().n_fns.get() + 1); + let mut stats = self.ccx.stats().borrow_mut(); + let iend = stats.n_llvm_insns; + stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart)); + stats.n_fns += 1; // Reset LLVM insn count to avoid compound costs. - self.ccx.stats().n_llvm_insns.set(self.istart); + stats.n_llvm_insns = self.istart; } } } @@ -590,7 +592,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance None => bug!("Instance `{:?}` not already declared", instance) }; - ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); + ccx.stats().borrow_mut().n_closures += 1; // The `uwtable` attribute according to LLVM is: // @@ -935,18 +937,14 @@ pub fn find_exported_symbols(tcx: TyCtxt) -> NodeSet { pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: IncrementalHashesMap, - rx: mpsc::Receiver>, - output_filenames: &OutputFilenames) + rx: mpsc::Receiver>) -> OngoingCrateTranslation { check_for_rustc_errors_attr(tcx); - let check_overflow = tcx.sess.overflow_checks(); let link_meta = link::build_link_meta(&incremental_hashes_map); let exported_symbol_node_ids = find_exported_symbols(tcx); - let shared_ccx = SharedCrateContext::new(tcx, - check_overflow, - output_filenames); + let shared_ccx = SharedCrateContext::new(tcx); // Translate the metadata. let (metadata_llcx, metadata_llmod, metadata, metadata_incr_hashes) = time(tcx.sess.time_passes(), "write metadata", || { @@ -974,13 +972,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, !tcx.sess.opts.output_types.should_trans() { let ongoing_translation = write::start_async_translation( tcx, - output_filenames, time_graph.clone(), link_meta, metadata, rx); - ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, metadata_module, true); + ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module); + ongoing_translation.translation_finished(tcx); assert_and_save_dep_graph(tcx, incremental_hashes_map, @@ -1002,7 +1000,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let ongoing_translation = write::start_async_translation( tcx, - output_filenames, time_graph.clone(), link_meta, metadata, @@ -1044,16 +1041,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; if let Some(allocator_module) = allocator_module { - ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, allocator_module, false); + ongoing_translation.submit_pre_translated_module_to_llvm(tcx, allocator_module); } - let codegen_unit_count = codegen_units.len(); - ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, - metadata_module, - codegen_unit_count == 0); - - let mut all_stats = Stats::default(); - let mut module_dispositions = tcx.sess.opts.incremental.as_ref().map(|_| Vec::new()); + ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module); // We sort the codegen units by size. This way we can schedule work for LLVM // a bit more efficiently. Note that "size" is defined rather crudely at the @@ -1066,217 +1057,57 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let mut total_trans_time = Duration::new(0, 0); + let mut all_stats = Stats::default(); - for (cgu_index, cgu) in codegen_units.into_iter().enumerate() { + for cgu in codegen_units.into_iter() { ongoing_translation.wait_for_signal_to_translate_item(); ongoing_translation.check_for_errors(tcx.sess); + let _timing_guard = time_graph + .as_ref() + .map(|time_graph| time_graph.start(write::TRANS_WORKER_TIMELINE, + write::TRANS_WORK_PACKAGE_KIND)); let start_time = Instant::now(); + all_stats.extend(tcx.compile_codegen_unit(*cgu.name())); + total_trans_time += start_time.elapsed(); - let module = { - let _timing_guard = time_graph - .as_ref() - .map(|time_graph| time_graph.start(write::TRANS_WORKER_TIMELINE, - write::TRANS_WORK_PACKAGE_KIND)); - let dep_node = cgu.work_product_dep_node(); - let ((stats, module), _) = - tcx.dep_graph.with_task(dep_node, - AssertDepGraphSafe(&shared_ccx), - AssertDepGraphSafe(cgu), - module_translation); - all_stats.extend(stats); - - if let Some(ref mut module_dispositions) = module_dispositions { - module_dispositions.push(module.disposition()); - } - - module - }; - - let time_to_translate = Instant::now().duration_since(start_time); - - // We assume that the cost to run LLVM on a CGU is proportional to - // the time we needed for translating it. - let cost = time_to_translate.as_secs() * 1_000_000_000 + - time_to_translate.subsec_nanos() as u64; - - total_trans_time += time_to_translate; - - let is_last_cgu = (cgu_index + 1) == codegen_unit_count; - - ongoing_translation.submit_translated_module_to_llvm(tcx.sess, - module, - cost, - is_last_cgu); ongoing_translation.check_for_errors(tcx.sess); } + ongoing_translation.translation_finished(tcx); + // Since the main thread is sometimes blocked during trans, we keep track // -Ztime-passes output manually. print_time_passes_entry(tcx.sess.time_passes(), "translate to LLVM IR", total_trans_time); - if let Some(module_dispositions) = module_dispositions { - assert_module_sources::assert_module_sources(tcx, &module_dispositions); - } - - fn module_translation<'a, 'tcx>( - scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, - args: AssertDepGraphSafe>>) - -> (Stats, ModuleTranslation) - { - // FIXME(#40304): We ought to be using the id as a key and some queries, I think. - let AssertDepGraphSafe(scx) = scx; - let AssertDepGraphSafe(cgu) = args; - - let cgu_name = cgu.name().to_string(); - let cgu_id = cgu.work_product_id(); - let symbol_name_hash = cgu.compute_symbol_name_hash(scx); - - // Check whether there is a previous work-product we can - // re-use. Not only must the file exist, and the inputs not - // be dirty, but the hash of the symbols we will generate must - // be the same. - let previous_work_product = - scx.dep_graph().previous_work_product(&cgu_id).and_then(|work_product| { - if work_product.input_hash == symbol_name_hash { - debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); - Some(work_product) - } else { - if scx.sess().opts.debugging_opts.incremental_info { - eprintln!("incremental: CGU `{}` invalidated because of \ - changed partitioning hash.", - cgu.name()); - } - debug!("trans_reuse_previous_work_products: \ - not reusing {:?} because hash changed to {:?}", - work_product, symbol_name_hash); - None - } - }); - - if let Some(buf) = previous_work_product { - // Don't need to translate this module. - let module = ModuleTranslation { - name: cgu_name, - symbol_name_hash, - source: ModuleSource::Preexisting(buf.clone()), - kind: ModuleKind::Regular, - }; - return (Stats::default(), module); - } - - // Instantiate translation items without filling out definitions yet... - let lcx = LocalCrateContext::new(scx, cgu); - let module = { - let ccx = CrateContext::new(scx, &lcx); - let trans_items = ccx.codegen_unit() - .items_in_deterministic_order(ccx.tcx()); - for &(trans_item, (linkage, visibility)) in &trans_items { - trans_item.predefine(&ccx, linkage, visibility); - } - - // ... and now that we have everything pre-defined, fill out those definitions. - for &(trans_item, _) in &trans_items { - trans_item.define(&ccx); - } - - // If this codegen unit contains the main function, also create the - // wrapper here - maybe_create_entry_wrapper(&ccx); - - // Run replace-all-uses-with for statics that need it - for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() { - unsafe { - let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g)); - llvm::LLVMReplaceAllUsesWith(old_g, bitcast); - llvm::LLVMDeleteGlobal(old_g); - } - } - - // Create the llvm.used variable - // This variable has type [N x i8*] and is stored in the llvm.metadata section - if !ccx.used_statics().borrow().is_empty() { - let name = CString::new("llvm.used").unwrap(); - let section = CString::new("llvm.metadata").unwrap(); - let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow()); - - unsafe { - let g = llvm::LLVMAddGlobal(ccx.llmod(), - val_ty(array).to_ref(), - name.as_ptr()); - llvm::LLVMSetInitializer(g, array); - llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); - llvm::LLVMSetSection(g, section.as_ptr()); - } - } - - // Finalize debuginfo - if ccx.sess().opts.debuginfo != NoDebugInfo { - debuginfo::finalize(&ccx); - } - - let llvm_module = ModuleLlvm { - llcx: ccx.llcx(), - llmod: ccx.llmod(), - }; - - // In LTO mode we inject the allocator shim into the existing - // module. - if ccx.sess().lto() { - if let Some(kind) = ccx.sess().allocator_kind.get() { - time(ccx.sess().time_passes(), "write allocator module", || { - unsafe { - allocator::trans(ccx.tcx(), &llvm_module, kind); - } - }); - } - } - - // Adjust exported symbols for MSVC dllimport - if ccx.sess().target.target.options.is_like_msvc && - ccx.sess().crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { - create_imps(ccx.sess(), &llvm_module); - } - - ModuleTranslation { - name: cgu_name, - symbol_name_hash, - source: ModuleSource::Translated(llvm_module), - kind: ModuleKind::Regular, - } - }; - - (lcx.into_stats(), module) + if tcx.sess.opts.incremental.is_some() { + DISPOSITIONS.with(|d| { + assert_module_sources::assert_module_sources(tcx, &d.borrow()); + }); } symbol_names_test::report_symbol_names(tcx); if shared_ccx.sess().trans_stats() { println!("--- trans stats ---"); - println!("n_glues_created: {}", all_stats.n_glues_created.get()); - println!("n_null_glues: {}", all_stats.n_null_glues.get()); - println!("n_real_glues: {}", all_stats.n_real_glues.get()); + println!("n_glues_created: {}", all_stats.n_glues_created); + println!("n_null_glues: {}", all_stats.n_null_glues); + println!("n_real_glues: {}", all_stats.n_real_glues); - println!("n_fns: {}", all_stats.n_fns.get()); - println!("n_inlines: {}", all_stats.n_inlines.get()); - println!("n_closures: {}", all_stats.n_closures.get()); + println!("n_fns: {}", all_stats.n_fns); + println!("n_inlines: {}", all_stats.n_inlines); + println!("n_closures: {}", all_stats.n_closures); println!("fn stats:"); - all_stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| { - insns_b.cmp(&insns_a) - }); - for tuple in all_stats.fn_stats.borrow().iter() { - match *tuple { - (ref name, insns) => { - println!("{} insns, {}", insns, *name); - } - } + all_stats.fn_stats.sort_by_key(|&(_, insns)| insns); + for &(ref name, insns) in all_stats.fn_stats.iter() { + println!("{} insns, {}", insns, *name); } } if shared_ccx.sess().count_llvm_insns() { - for (k, v) in all_stats.llvm_insns.borrow().iter() { + for (k, v) in all_stats.llvm_insns.iter() { println!("{:7} {}", *v, *k); } } @@ -1290,6 +1121,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ongoing_translation } +// FIXME(#42293) hopefully once red/green is enabled we're testing everything +// via a method that doesn't require this! +thread_local!(static DISPOSITIONS: RefCell> = Default::default()); + fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: IncrementalHashesMap, metadata_incr_hashes: EncodedMetadataHashes, @@ -1524,11 +1359,185 @@ fn is_translated_function(tcx: TyCtxt, id: DefId) -> bool { }) } +fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cgu: InternedString) -> Stats { + // FIXME(#42293) needs red/green tracking to avoid failing a bunch of + // existing tests + let cgu = tcx.dep_graph.with_ignore(|| { + tcx.codegen_unit(cgu) + }); + + let start_time = Instant::now(); + let dep_node = cgu.work_product_dep_node(); + let ((stats, module), _) = + tcx.dep_graph.with_task(dep_node, + AssertDepGraphSafe(tcx), + AssertDepGraphSafe(cgu), + module_translation); + let time_to_translate = start_time.elapsed(); + + if tcx.sess.opts.incremental.is_some() { + DISPOSITIONS.with(|d| { + d.borrow_mut().push(module.disposition()); + }); + } + + // We assume that the cost to run LLVM on a CGU is proportional to + // the time we needed for translating it. + let cost = time_to_translate.as_secs() * 1_000_000_000 + + time_to_translate.subsec_nanos() as u64; + + write::submit_translated_module_to_llvm(tcx, + module, + cost); + return stats; + + fn module_translation<'a, 'tcx>( + tcx: AssertDepGraphSafe>, + args: AssertDepGraphSafe>>) + -> (Stats, ModuleTranslation) + { + // FIXME(#40304): We ought to be using the id as a key and some queries, I think. + let AssertDepGraphSafe(tcx) = tcx; + let AssertDepGraphSafe(cgu) = args; + + let cgu_name = cgu.name().to_string(); + let cgu_id = cgu.work_product_id(); + let symbol_name_hash = cgu.compute_symbol_name_hash(tcx); + + // Check whether there is a previous work-product we can + // re-use. Not only must the file exist, and the inputs not + // be dirty, but the hash of the symbols we will generate must + // be the same. + let previous_work_product = + tcx.dep_graph.previous_work_product(&cgu_id).and_then(|work_product| { + if work_product.input_hash == symbol_name_hash { + debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); + Some(work_product) + } else { + if tcx.sess.opts.debugging_opts.incremental_info { + eprintln!("incremental: CGU `{}` invalidated because of \ + changed partitioning hash.", + cgu.name()); + } + debug!("trans_reuse_previous_work_products: \ + not reusing {:?} because hash changed to {:?}", + work_product, symbol_name_hash); + None + } + }); + + if let Some(buf) = previous_work_product { + // Don't need to translate this module. + let module = ModuleTranslation { + name: cgu_name, + symbol_name_hash, + source: ModuleSource::Preexisting(buf.clone()), + kind: ModuleKind::Regular, + }; + return (Stats::default(), module); + } + + // Instantiate translation items without filling out definitions yet... + let scx = SharedCrateContext::new(tcx); + let lcx = LocalCrateContext::new(&scx, cgu); + let module = { + let ccx = CrateContext::new(&scx, &lcx); + let trans_items = ccx.codegen_unit() + .items_in_deterministic_order(ccx.tcx()); + for &(trans_item, (linkage, visibility)) in &trans_items { + trans_item.predefine(&ccx, linkage, visibility); + } + + // ... and now that we have everything pre-defined, fill out those definitions. + for &(trans_item, _) in &trans_items { + trans_item.define(&ccx); + } + + // If this codegen unit contains the main function, also create the + // wrapper here + maybe_create_entry_wrapper(&ccx); + + // Run replace-all-uses-with for statics that need it + for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() { + unsafe { + let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g)); + llvm::LLVMReplaceAllUsesWith(old_g, bitcast); + llvm::LLVMDeleteGlobal(old_g); + } + } + + // Create the llvm.used variable + // This variable has type [N x i8*] and is stored in the llvm.metadata section + if !ccx.used_statics().borrow().is_empty() { + let name = CString::new("llvm.used").unwrap(); + let section = CString::new("llvm.metadata").unwrap(); + let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow()); + + unsafe { + let g = llvm::LLVMAddGlobal(ccx.llmod(), + val_ty(array).to_ref(), + name.as_ptr()); + llvm::LLVMSetInitializer(g, array); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); + llvm::LLVMSetSection(g, section.as_ptr()); + } + } + + // Finalize debuginfo + if ccx.sess().opts.debuginfo != NoDebugInfo { + debuginfo::finalize(&ccx); + } + + let llvm_module = ModuleLlvm { + llcx: ccx.llcx(), + llmod: ccx.llmod(), + }; + + // In LTO mode we inject the allocator shim into the existing + // module. + if ccx.sess().lto() { + if let Some(kind) = ccx.sess().allocator_kind.get() { + time(ccx.sess().time_passes(), "write allocator module", || { + unsafe { + allocator::trans(ccx.tcx(), &llvm_module, kind); + } + }); + } + } + + // Adjust exported symbols for MSVC dllimport + if ccx.sess().target.target.options.is_like_msvc && + ccx.sess().crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { + create_imps(ccx.sess(), &llvm_module); + } + + ModuleTranslation { + name: cgu_name, + symbol_name_hash, + source: ModuleSource::Translated(llvm_module), + kind: ModuleKind::Regular, + } + }; + + (lcx.into_stats(), module) + } +} + pub fn provide_local(providers: &mut Providers) { providers.collect_and_partition_translation_items = collect_and_partition_translation_items; providers.is_translated_function = is_translated_function; + + providers.codegen_unit = |tcx, name| { + let (_, all) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); + all.iter() + .find(|cgu| *cgu.name() == name) + .cloned() + .expect(&format!("failed to find cgu with name {:?}", name)) + }; + providers.compile_codegen_unit = compile_codegen_unit; } pub fn provide_extern(providers: &mut Providers) { diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 8a585e72f59ed..41a238ea8e3fa 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -101,11 +101,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn count_insn(&self, category: &str) { if self.ccx.sess().trans_stats() { - self.ccx.stats().n_llvm_insns.set(self.ccx.stats().n_llvm_insns.get() + 1); + self.ccx.stats().borrow_mut().n_llvm_insns += 1; } if self.ccx.sess().count_llvm_insns() { - let mut h = self.ccx.stats().llvm_insns.borrow_mut(); - *h.entry(category.to_string()).or_insert(0) += 1; + *self.ccx.stats() + .borrow_mut() + .llvm_insns + .entry(category.to_string()) + .or_insert(0) += 1; } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index a1666fa523195..8b18bf2e1ff1f 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -24,10 +24,11 @@ use monomorphize::Instance; use partitioning::CodegenUnit; use type_::Type; use rustc_data_structures::base_n; -use rustc::session::config::{self, NoDebugInfo, OutputFilenames}; +use rustc::middle::trans::Stats; use rustc::session::Session; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::session::config::{self, NoDebugInfo}; use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; use std::ffi::{CStr, CString}; @@ -40,36 +41,6 @@ use std::marker::PhantomData; use syntax::symbol::InternedString; use abi::Abi; -#[derive(Clone, Default)] -pub struct Stats { - pub n_glues_created: Cell, - pub n_null_glues: Cell, - pub n_real_glues: Cell, - pub n_fns: Cell, - pub n_inlines: Cell, - pub n_closures: Cell, - pub n_llvm_insns: Cell, - pub llvm_insns: RefCell>, - // (ident, llvm-instructions) - pub fn_stats: RefCell >, -} - -impl Stats { - pub fn extend(&mut self, stats: Stats) { - self.n_glues_created.set(self.n_glues_created.get() + stats.n_glues_created.get()); - self.n_null_glues.set(self.n_null_glues.get() + stats.n_null_glues.get()); - self.n_real_glues.set(self.n_real_glues.get() + stats.n_real_glues.get()); - self.n_fns.set(self.n_fns.get() + stats.n_fns.get()); - self.n_inlines.set(self.n_inlines.get() + stats.n_inlines.get()); - self.n_closures.set(self.n_closures.get() + stats.n_closures.get()); - self.n_llvm_insns.set(self.n_llvm_insns.get() + stats.n_llvm_insns.get()); - self.llvm_insns.borrow_mut().extend( - stats.llvm_insns.borrow().iter() - .map(|(key, value)| (key.clone(), value.clone()))); - self.fn_stats.borrow_mut().append(&mut *stats.fn_stats.borrow_mut()); - } -} - /// The shared portion of a `CrateContext`. There is one `SharedCrateContext` /// per crate. The data here is shared between all compilation units of the /// crate, so it must not contain references to any LLVM data structures @@ -77,10 +48,7 @@ impl Stats { pub struct SharedCrateContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, check_overflow: bool, - use_dll_storage_attrs: bool, - - output_filenames: &'a OutputFilenames, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -90,7 +58,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { pub struct LocalCrateContext<'a, 'tcx: 'a> { llmod: ModuleRef, llcx: ContextRef, - stats: Stats, + stats: RefCell, codegen_unit: Arc>, /// Cache instances of monomorphic and polymorphic items @@ -253,10 +221,7 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont } impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { - pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, - check_overflow: bool, - output_filenames: &'b OutputFilenames) - -> SharedCrateContext<'b, 'tcx> { + pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>) -> SharedCrateContext<'b, 'tcx> { // An interesting part of Windows which MSVC forces our hand on (and // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` // attributes in LLVM IR as well as native dependencies (in C these @@ -302,11 +267,12 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { // start) and then strongly recommending static linkage on MSVC! let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc; + let check_overflow = tcx.sess.overflow_checks(); + SharedCrateContext { tcx, check_overflow, use_dll_storage_attrs, - output_filenames, } } @@ -337,10 +303,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn use_dll_storage_attrs(&self) -> bool { self.use_dll_storage_attrs } - - pub fn output_filenames(&self) -> &OutputFilenames { - self.output_filenames - } } impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { @@ -375,7 +337,7 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { let local_ccx = LocalCrateContext { llmod, llcx, - stats: Stats::default(), + stats: RefCell::new(Stats::default()), codegen_unit, instances: RefCell::new(FxHashMap()), vtables: RefCell::new(FxHashMap()), @@ -440,7 +402,7 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { } pub fn into_stats(self) -> Stats { - self.stats + self.stats.into_inner() } } @@ -525,7 +487,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().lltypes } - pub fn stats<'a>(&'a self) -> &'a Stats { + pub fn stats<'a>(&'a self) -> &'a RefCell { &self.local().stats } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 333f7b1c029c1..8a89bfee4ac26 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -822,9 +822,9 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, let gcov_cu_info = [ path_to_mdstring(debug_context.llcontext, - &scc.output_filenames().with_extension("gcno")), + &scc.tcx().output_filenames(LOCAL_CRATE).with_extension("gcno")), path_to_mdstring(debug_context.llcontext, - &scc.output_filenames().with_extension("gcda")), + &scc.tcx().output_filenames(LOCAL_CRATE).with_extension("gcda")), cu_desc_metadata, ]; let gcov_metadata = llvm::LLVMMDNodeInContext(debug_context.llcontext, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 1572f1dc230c1..453b98a1d74f7 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -20,9 +20,8 @@ use llvm::{ValueRef}; use llvm; use meth; use monomorphize; -use rustc::traits; use rustc::ty::layout::LayoutTyper; -use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; +use rustc::ty::{self, Ty}; use value::Value; pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef) diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index e62924a54d757..2be7a81b1cd49 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -187,7 +187,7 @@ pub fn resolve<'a, 'tcx>( _ => { if Some(def_id) == tcx.lang_items().drop_in_place_fn() { let ty = substs.type_at(0); - if common::type_needs_drop(tcx, ty) { + if type_needs_drop(tcx, ty) { debug!(" => nontrivial drop glue"); ty::InstanceDef::DropGlue(def_id, Some(ty)) } else { diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 65cf24e8c6e03..9b617c35d9319 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -104,7 +104,6 @@ use collector::InliningMap; use common; -use context::SharedCrateContext; use rustc::dep_graph::{DepNode, WorkProductId}; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; @@ -155,13 +154,11 @@ pub trait CodegenUnitExt<'tcx> { self.work_product_id().to_dep_node() } - fn compute_symbol_name_hash<'a>(&self, - scx: &SharedCrateContext<'a, 'tcx>) - -> u64 { + fn compute_symbol_name_hash<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> u64 { let mut state = IchHasher::new(); - let all_items = self.items_in_deterministic_order(scx.tcx()); + let all_items = self.items_in_deterministic_order(tcx); for (item, (linkage, visibility)) in all_items { - let symbol_name = item.symbol_name(scx.tcx()); + let symbol_name = item.symbol_name(tcx); symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); linkage.hash(&mut state); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fd0167be2b98f..0c0748cf673c1 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -176,6 +176,11 @@ pub fn run_core(search_paths: SearchPaths, let arena = DroplessArena::new(); let arenas = GlobalArenas::new(); let hir_map = hir_map::map_crate(&mut hir_forest, defs); + let output_filenames = driver::build_output_filenames(&input, + &None, + &None, + &[], + &sess); abort_on_err(driver::phase_3_run_analysis_passes(&sess, &*cstore, @@ -185,7 +190,8 @@ pub fn run_core(search_paths: SearchPaths, &arena, &arenas, &name, - |tcx, analysis, _, result| { + &output_filenames, + |tcx, analysis, _, _, result| { if let Err(_) = result { sess.fatal("Compilation failed, aborting rustdoc"); }