trans: Make translation of statics collector-driven.

This commit is contained in:
Michael Woerister 2016-05-06 20:02:09 -04:00
parent 3fa1cdf23c
commit 891c2a082f
3 changed files with 220 additions and 136 deletions

View File

@ -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(&sect) {
ccx.sess().fatal(&format!("Illegal null byte in link_section value: `{}`", &sect));
}
@ -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);

View File

@ -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)
}
}

View File

@ -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<llvm::Linkage> {
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<llvm::Linkage> {
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)
}
}
}
}