From 891c2a082fd562744b4495ed7bd0602414e93f2b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 6 May 2016 20:02:09 -0400 Subject: [PATCH] trans: Make translation of statics collector-driven. --- src/librustc_trans/base.rs | 46 ++++-- src/librustc_trans/consts.rs | 52 ++++--- src/librustc_trans/trans_item.rs | 258 ++++++++++++++++++------------- 3 files changed, 220 insertions(+), 136 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 590220f0c8b..40ae5025180 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -2249,8 +2249,10 @@ pub fn update_linkage(ccx: &CrateContext, } } -fn set_global_section(ccx: &CrateContext, llval: ValueRef, i: &hir::Item) { - if let Some(sect) = attr::first_attr_value_str_by_name(&i.attrs, "link_section") { +pub fn set_link_section(ccx: &CrateContext, + llval: ValueRef, + attrs: &[ast::Attribute]) { + if let Some(sect) = attr::first_attr_value_str_by_name(attrs, "link_section") { if contains_null(§) { ccx.sess().fatal(&format!("Illegal null byte in link_section value: `{}`", §)); } @@ -2280,7 +2282,7 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) { let empty_substs = ccx.empty_substs_for_def_id(def_id); let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val; trans_fn(ccx, &decl, &body, llfn, empty_substs, item.id); - set_global_section(ccx, llfn, item); + set_link_section(ccx, llfn, &item.attrs); update_linkage(ccx, llfn, Some(item.id), @@ -2336,13 +2338,9 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) { enum_variant_size_lint(ccx, enum_definition, item.span, item.id); } } - hir::ItemStatic(_, m, ref expr) => { - let g = match consts::trans_static(ccx, m, expr, item.id, &item.attrs) { - Ok(g) => g, - Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()), - }; - set_global_section(ccx, g, item); - update_linkage(ccx, g, Some(item.id), OriginalTranslation); + hir::ItemStatic(..) => { + // Don't do anything here. Translation of statics has been moved to + // being "collector-driven". } _ => {} } @@ -2700,6 +2698,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let codegen_units = collect_and_partition_translation_items(&shared_ccx); let codegen_unit_count = codegen_units.len(); + assert!(tcx.sess.opts.cg.codegen_units == codegen_unit_count || tcx.sess.opts.debugging_opts.incremental.is_some()); @@ -2723,6 +2722,33 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; } + // Instantiate translation items without filling out definitions yet... + for ccx in crate_context_list.iter() { + for (&trans_item, &linkage) in &ccx.codegen_unit().items { + trans_item.predefine(&ccx, linkage); + } + } + + // ... and now that we have everything pre-defined, fill out those definitions. + for ccx in crate_context_list.iter() { + for (&trans_item, _) in &ccx.codegen_unit().items { + match trans_item { + TransItem::Static(node_id) => { + let item = ccx.tcx().map.expect_item(node_id); + if let hir::ItemStatic(_, m, ref expr) = item.node { + match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) { + Ok(_) => { /* Cool, everything's alright. */ }, + Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()), + }; + } else { + span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") + } + } + _ => { } + } + } + } + { let ccx = crate_context_list.get_ccx(0); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 5596ab0d819..1a38baeff37 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -1017,22 +1017,29 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) { let llty = type_of::type_of(ccx, ty); - match ccx.tcx().map.get(id) { + let (g, attrs) = match ccx.tcx().map.get(id) { hir_map::NodeItem(&hir::Item { - span, node: hir::ItemStatic(..), .. + ref attrs, span, node: hir::ItemStatic(..), .. }) => { - // If this static came from an external crate, then - // we need to get the symbol from metadata instead of - // using the current crate's name/version - // information in the hash of the symbol - debug!("making {}", sym); + // Make sure that this is never executed for something inlined. + assert!(!ccx.external_srcs().borrow().contains_key(&id)); - // Create the global before evaluating the initializer; - // this is necessary to allow recursive statics. - declare::define_global(ccx, &sym, llty).unwrap_or_else(|| { - ccx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", sym)) - }) + let defined_in_current_codegen_unit = ccx.codegen_unit() + .items + .contains_key(&TransItem::Static(id)); + if defined_in_current_codegen_unit { + if declare::get_declared_value(ccx, &sym).is_none() { + span_bug!(span, "trans: Static not properly pre-defined?"); + } + } else { + if declare::get_declared_value(ccx, &sym).is_some() { + span_bug!(span, "trans: Conflicting symbol names for static?"); + } + } + + let g = declare::define_global(ccx, &sym, llty).unwrap(); + + (g, attrs) } hir_map::NodeForeignItem(&hir::ForeignItem { @@ -1083,17 +1090,19 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) declare::declare_global(ccx, &sym, llty) }; - for attr in attrs { - if attr.check_name("thread_local") { - llvm::set_thread_local(g, true); - } - } - - g + (g, attrs) } item => bug!("get_static: expected static, found {:?}", item) + }; + + for attr in attrs { + if attr.check_name("thread_local") { + llvm::set_thread_local(g, true); + } } + + g } else { // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global @@ -1197,6 +1206,9 @@ pub fn trans_static(ccx: &CrateContext, "thread_local") { llvm::set_thread_local(g, true); } + + base::set_link_section(ccx, g, attrs); + Ok(g) } } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index d7c5c41a156..92fddd7d77d 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -14,7 +14,9 @@ //! item-path. This is used for unit testing the code that generates //! paths etc in all kinds of annoying scenarios. -use base::llvm_linkage_by_name; +use base; +use context::CrateContext; +use declare; use glue::DropGlueKind; use llvm; use monomorphize::Instance; @@ -26,6 +28,8 @@ use std::hash::{Hash, Hasher}; use syntax::ast::{self, NodeId}; use syntax::attr; use syntax::parse::token; +use type_of; + #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum TransItem<'tcx> { @@ -54,6 +58,153 @@ impl<'tcx> Hash for TransItem<'tcx> { } } + +impl<'tcx> TransItem<'tcx> { + + pub fn predefine<'ccx>(&self, + ccx: &CrateContext<'ccx, 'tcx>, + linkage: llvm::Linkage) { + match *self { + TransItem::Static(node_id) => { + TransItem::predefine_static(ccx, node_id, linkage); + } + _ => { + // Not yet implemented + } + } + } + + fn predefine_static<'a>(ccx: &CrateContext<'a, 'tcx>, + node_id: ast::NodeId, + linkage: llvm::Linkage) { + let def_id = ccx.tcx().map.local_def_id(node_id); + let ty = ccx.tcx().lookup_item_type(def_id).ty; + let llty = type_of::type_of(ccx, ty); + + match ccx.tcx().map.get(node_id) { + hir::map::NodeItem(&hir::Item { + span, node: hir::ItemStatic(..), .. + }) => { + let instance = Instance::mono(ccx.shared(), def_id); + let sym = instance.symbol_name(ccx.shared()); + debug!("making {}", sym); + + let g = declare::define_global(ccx, &sym, llty).unwrap_or_else(|| { + ccx.sess().span_fatal(span, + &format!("symbol `{}` is already defined", sym)) + }); + + llvm::SetLinkage(g, linkage); + } + + item => bug!("predefine_static: expected static, found {:?}", item) + } + } + + pub fn requests_inline<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + match *self { + TransItem::Fn(ref instance) => { + let attributes = tcx.get_attrs(instance.def); + attr::requests_inline(&attributes[..]) + } + TransItem::DropGlue(..) => true, + TransItem::Static(..) => false, + } + } + + pub fn is_from_extern_crate(&self) -> bool { + match *self { + TransItem::Fn(ref instance) => !instance.def.is_local(), + TransItem::DropGlue(..) | + TransItem::Static(..) => false, + } + } + + pub fn is_lazily_instantiated(&self) -> bool { + match *self { + TransItem::Fn(ref instance) => !instance.substs.types.is_empty(), + TransItem::DropGlue(..) => true, + TransItem::Static(..) => false, + } + } + + pub fn explicit_linkage<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + let def_id = match *self { + TransItem::Fn(ref instance) => instance.def, + TransItem::Static(node_id) => tcx.map.local_def_id(node_id), + TransItem::DropGlue(..) => return None, + }; + + 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) { + Some(linkage) + } else { + let span = tcx.map.span_if_local(def_id); + if let Some(span) = span { + tcx.sess.span_fatal(span, "invalid linkage specified") + } else { + tcx.sess.fatal(&format!("invalid linkage specified: {}", name)) + } + } + } else { + None + } + } + + pub fn to_string<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { + let hir_map = &tcx.map; + + return match *self { + TransItem::DropGlue(dg) => { + let mut s = String::with_capacity(32); + match dg { + DropGlueKind::Ty(_) => s.push_str("drop-glue "), + DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "), + }; + push_unique_type_name(tcx, dg.ty(), &mut s); + s + } + TransItem::Fn(instance) => { + to_string_internal(tcx, "fn ", instance) + }, + TransItem::Static(node_id) => { + let def_id = hir_map.local_def_id(node_id); + let instance = Instance::new(def_id, + tcx.mk_substs(subst::Substs::empty())); + to_string_internal(tcx, "static ", instance) + }, + }; + + fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx,'tcx>, + prefix: &str, + instance: Instance<'tcx>) + -> String { + let mut result = String::with_capacity(32); + result.push_str(prefix); + push_instance_as_string(tcx, instance, &mut result); + result + } + } + + pub fn to_raw_string(&self) -> String { + match *self { + TransItem::DropGlue(dg) => { + format!("DropGlue({})", dg.ty() as *const _ as usize) + } + TransItem::Fn(instance) => { + format!("Fn({:?}, {})", + instance.def, + instance.substs as *const _ as usize) + } + TransItem::Static(id) => { + format!("Static({:?})", id) + } + } + } +} + + //=----------------------------------------------------------------------------- // TransItem String Keys //=----------------------------------------------------------------------------- @@ -277,108 +428,3 @@ pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, push_unique_type_name(tcx, ty, &mut output); output } - -impl<'tcx> TransItem<'tcx> { - - pub fn requests_inline<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { - match *self { - TransItem::Fn(ref instance) => { - let attributes = tcx.get_attrs(instance.def); - attr::requests_inline(&attributes[..]) - } - TransItem::DropGlue(..) => true, - TransItem::Static(..) => false, - } - } - - pub fn is_from_extern_crate(&self) -> bool { - match *self { - TransItem::Fn(ref instance) => !instance.def.is_local(), - TransItem::DropGlue(..) | - TransItem::Static(..) => false, - } - } - - pub fn is_lazily_instantiated(&self) -> bool { - match *self { - TransItem::Fn(ref instance) => !instance.substs.types.is_empty(), - TransItem::DropGlue(..) => true, - TransItem::Static(..) => false, - } - } - - pub fn explicit_linkage<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { - let def_id = match *self { - TransItem::Fn(ref instance) => instance.def, - TransItem::Static(node_id) => tcx.map.local_def_id(node_id), - TransItem::DropGlue(..) => return None, - }; - - let attributes = tcx.get_attrs(def_id); - if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") { - if let Some(linkage) = llvm_linkage_by_name(&name) { - Some(linkage) - } else { - let span = tcx.map.span_if_local(def_id); - if let Some(span) = span { - tcx.sess.span_fatal(span, "invalid linkage specified") - } else { - tcx.sess.fatal(&format!("invalid linkage specified: {}", name)) - } - } - } else { - None - } - } - - pub fn to_string<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { - let hir_map = &tcx.map; - - return match *self { - TransItem::DropGlue(dg) => { - let mut s = String::with_capacity(32); - match dg { - DropGlueKind::Ty(_) => s.push_str("drop-glue "), - DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "), - }; - push_unique_type_name(tcx, dg.ty(), &mut s); - s - } - TransItem::Fn(instance) => { - to_string_internal(tcx, "fn ", instance) - }, - TransItem::Static(node_id) => { - let def_id = hir_map.local_def_id(node_id); - let empty_substs = tcx.mk_substs(subst::Substs::empty()); - let instance = Instance::new(def_id, empty_substs); - to_string_internal(tcx, "static ", instance) - }, - }; - - fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prefix: &str, - instance: Instance<'tcx>) - -> String { - let mut result = String::with_capacity(32); - result.push_str(prefix); - push_instance_as_string(tcx, instance, &mut result); - result - } - } - - pub fn to_raw_string(&self) -> String { - match *self { - TransItem::DropGlue(dg) => { - format!("DropGlue({})", dg.ty() as *const _ as usize) - } - TransItem::Fn(instance) => { - format!("Fn({:?}, {})", - instance.def, - instance.substs as *const _ as usize) - } - TransItem::Static(id) => { - format!("Static({:?})", id) - } - } - } -}