///
/// I will do my best to describe this structure, but these
/// comments are reverse-engineered and may be inaccurate. -NDM
+#[derive(Clone)]
pub struct FnType {
/// The LLVM types of each argument.
pub args: Vec<ArgType>,
}
}
+pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+ t: ty::Ty<'tcx>,
+ prefix: &str)
+ -> String {
+ let empty_def_path = DefPath {
+ data: vec![],
+ krate: cstore::LOCAL_CRATE,
+ };
+ let hash = get_symbol_hash(scx, &empty_def_path, t, &[]);
+ let path = [token::intern_and_get_ident(prefix)];
+ mangle(path.iter().cloned(), Some(&hash[..]))
+}
+
/// Only symbols that are invisible outside their compilation unit should use a
/// name generated by this function.
pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
}
-/// Set the appropriate linkage for an LLVM `ValueRef` (function or global).
-/// If the `llval` is the direct translation of a specific Rust item, `id`
-/// should be set to the `NodeId` of that item. (This mapping should be
-/// 1-to-1, so monomorphizations and drop/visit glue should have `id` set to
-/// `None`.)
-pub fn update_linkage(ccx: &CrateContext,
- llval: ValueRef,
- id: Option<ast::NodeId>) {
- if let Some(id) = id {
- let item = ccx.tcx().map.get(id);
- if let hir_map::NodeItem(i) = item {
- if let Some(name) = attr::first_attr_value_str_by_name(&i.attrs, "linkage") {
- if let Some(linkage) = llvm_linkage_by_name(&name) {
- llvm::SetLinkage(llval, linkage);
- } else {
- ccx.sess().span_fatal(i.span, "invalid linkage specified");
- }
- return;
- }
- }
- }
-
- let (is_reachable, is_generic) = if let Some(id) = id {
- (ccx.reachable().contains(&id), false)
- } else {
- (false, true)
- };
-
- // We need external linkage for items reachable from other translation units, this include
- // other codegen units in case of parallel compilations.
- if is_reachable || ccx.sess().opts.cg.codegen_units > 1 {
- if is_generic {
- // This only happens with multiple codegen units, in which case we need to use weak_odr
- // linkage because other crates might expose the same symbol. We cannot use
- // linkonce_odr here because the symbol might then get dropped before the other codegen
- // units get to link it.
- llvm::SetUniqueComdat(ccx.llmod(), llval);
- llvm::SetLinkage(llval, llvm::WeakODRLinkage);
- } else {
- llvm::SetLinkage(llval, llvm::ExternalLinkage);
- }
- } else {
- llvm::SetLinkage(llval, llvm::InternalLinkage);
- }
-}
-
pub fn set_link_section(ccx: &CrateContext,
llval: ValueRef,
attrs: &[ast::Attribute]) {
// ... 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")
- }
- }
- TransItem::Fn(instance) => {
- trans_instance(&ccx, instance);
- }
- _ => { }
- }
+ for (trans_item, _) in &ccx.codegen_unit().items {
+ trans_item.define(&ccx);
}
}
let mut item_keys: Vec<_> = items
.iter()
.map(|i| {
- let mut output = i.to_string(scx);
+ let mut output = i.to_string(scx.tcx());
output.push_str(" @@");
let mut empty = Vec::new();
let mut cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
// We've been here already, no need to search again.
return;
}
- debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx));
+ debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx.tcx()));
let mut neighbors = Vec::new();
let recursion_depth_reset;
recursion_depths.insert(def_id, depth);
}
- debug!("END collect_items_rec({})", starting_point.to_string(scx));
+ debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx()));
}
fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let operand_ty = monomorphize::apply_param_substs(tcx,
self.param_substs,
&mt.ty);
- self.output.push(TransItem::DropGlue(DropGlueKind::Ty(operand_ty)));
+ let ty = glue::get_drop_glue_type(tcx, operand_ty);
+ self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
} else {
bug!("Has the drop_in_place() intrinsic's signature changed?")
}
let mut item_keys = FnvHashMap();
for (item, item_state) in trans_items.iter() {
- let k = item.to_string(scx);
+ let k = item.to_string(scx.tcx());
if item_keys.contains_key(&k) {
let prev: (TransItem, TransItemState) = item_keys[&k];
let mut generated = FnvHashSet();
for (item, item_state) in trans_items.iter() {
- let item_key = item.to_string(scx);
+ let item_key = item.to_string(scx.tcx());
match *item_state {
TransItemState::PredictedAndGenerated => {
use session::config::NoDebugInfo;
use session::Session;
use util::sha2::Sha256;
-use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
+use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap};
use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell};
use std::str;
use syntax::ast;
use syntax::parse::token::InternedString;
+use abi::FnType;
pub struct Stats {
pub n_glues_created: Cell<usize>,
mir_map: &'a MirMap<'tcx>,
mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,
- available_monomorphizations: RefCell<FnvHashSet<String>>,
- available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
use_dll_storage_attrs: bool,
translation_items: RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>>,
codegen_unit: CodegenUnit<'tcx>,
needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
fn_pointer_shims: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
- drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>>,
+ drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, (ValueRef, FnType)>>,
/// Track mapping of external ids to local items imported for inlining
external: RefCell<DefIdMap<Option<ast::NodeId>>>,
/// Backwards version of the `external` map (inlined items to where they
},
check_overflow: check_overflow,
check_drop_flag_for_sanity: check_drop_flag_for_sanity,
- available_monomorphizations: RefCell::new(FnvHashSet()),
- available_drop_glues: RefCell::new(FnvHashMap()),
use_dll_storage_attrs: use_dll_storage_attrs,
translation_items: RefCell::new(FnvHashMap()),
trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
&self.local().fn_pointer_shims
}
- pub fn drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>> {
+ pub fn drop_glues<'a>(&'a self)
+ -> &'a RefCell<FnvHashMap<DropGlueKind<'tcx>, (ValueRef, FnType)>> {
&self.local().drop_glues
}
&self.shared.stats
}
- pub fn available_monomorphizations<'a>(&'a self) -> &'a RefCell<FnvHashSet<String>> {
- &self.shared.available_monomorphizations
- }
-
- pub fn available_drop_glues(&self) -> &RefCell<FnvHashMap<DropGlueKind<'tcx>, String>> {
- &self.shared.available_drop_glues
- }
-
pub fn int_type(&self) -> Type {
self.local().int_type
}
}
}
-
/// Declare a Rust function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will
/// return panic if the name already has a definition associated with it. This
/// can happen with #[no_mangle] or #[export_name], for example.
-pub fn define_internal_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- name: &str,
- fn_type: ty::Ty<'tcx>) -> ValueRef {
+pub fn define_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ name: &str,
+ fn_type: ty::Ty<'tcx>) -> ValueRef {
if get_defined_value(ccx, name).is_some() {
ccx.sess().fatal(&format!("symbol `{}` already defined", name))
} else {
- let llfn = declare_fn(ccx, name, fn_type);
- llvm::SetLinkage(llfn, llvm::InternalLinkage);
- llfn
+ declare_fn(ccx, name, fn_type)
}
}
+/// Declare a Rust function with an intention to define it.
+///
+/// Use this function when you intend to define a function. This function will
+/// return panic if the name already has a definition associated with it. This
+/// can happen with #[no_mangle] or #[export_name], for example.
+pub fn define_internal_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ name: &str,
+ fn_type: ty::Ty<'tcx>) -> ValueRef {
+ let llfn = define_fn(ccx, name, fn_type);
+ llvm::SetLinkage(llfn, llvm::InternalLinkage);
+ llfn
+}
+
/// Get declared value by name.
pub fn get_declared_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
use std;
-use attributes;
-use back::symbol_names;
use llvm;
use llvm::{ValueRef, get_param};
use middle::lang_items::ExchangeFreeFnLangItem;
use rustc::ty::subst::{Substs};
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use abi::{Abi, FnType};
use adt;
use adt::GetDtorType; // for tcx.dtor_type()
use base::*;
use collector;
use common::*;
use debuginfo::DebugLoc;
-use declare;
use expr;
use machine::*;
use monomorphize;
fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
g: DropGlueKind<'tcx>) -> ValueRef {
- debug!("make drop glue for {:?}", g);
let g = g.map_ty(|t| get_drop_glue_type(ccx.tcx(), t));
- debug!("drop glue type {:?}", g);
match ccx.drop_glues().borrow().get(&g) {
- Some(&glue) => return glue,
- _ => { }
+ Some(&(glue, _)) => glue,
+ None => { bug!("Could not find drop glue for {:?} -- {} -- {}",
+ g,
+ TransItem::DropGlue(g).to_raw_string(),
+ ccx.codegen_unit().name) }
}
- let t = g.ty();
+}
+pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ g: DropGlueKind<'tcx>) {
let tcx = ccx.tcx();
- let sig = ty::FnSig {
- inputs: vec![tcx.mk_mut_ptr(tcx.types.i8)],
- output: ty::FnOutput::FnConverging(tcx.mk_nil()),
- variadic: false,
- };
- // Create a FnType for fn(*mut i8) and substitute the real type in
- // later - that prevents FnType from splitting fat pointers up.
- let mut fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
- fn_ty.args[0].original_ty = type_of(ccx, t).ptr_to();
- let llfnty = fn_ty.llvm_type(ccx);
-
- // To avoid infinite recursion, don't `make_drop_glue` until after we've
- // added the entry to the `drop_glues` cache.
- if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&g) {
- let llfn = declare::declare_cfn(ccx, &old_sym, llfnty);
- ccx.drop_glues().borrow_mut().insert(g, llfn);
- return llfn;
- };
-
- let suffix = match g {
- DropGlueKind::Ty(_) => "drop",
- DropGlueKind::TyContents(_) => "drop_contents",
- };
-
- let fn_nm = symbol_names::internal_name_from_type_and_suffix(ccx, t, suffix);
- assert!(declare::get_defined_value(ccx, &fn_nm).is_none());
- let llfn = declare::declare_cfn(ccx, &fn_nm, llfnty);
- attributes::set_frame_pointer_elimination(ccx, llfn);
- ccx.available_drop_glues().borrow_mut().insert(g, fn_nm);
- ccx.drop_glues().borrow_mut().insert(g, llfn);
-
- let _s = StatRecorder::new(ccx, format!("drop {:?}", t));
+ assert_eq!(g.ty(), get_drop_glue_type(tcx, g.ty()));
+ let (llfn, fn_ty) = ccx.drop_glues().borrow().get(&g).unwrap().clone();
let (arena, fcx): (TypedArena<_>, FunctionContext);
arena = TypedArena::new();
let bcx = fcx.init(false, None);
- update_linkage(ccx, llfn, None);
-
ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1);
// All glue functions take values passed *by alias*; this is a
// requirement since in many contexts glue is invoked indirectly and
let bcx = make_drop_glue(bcx, get_param(llfn, 0), g);
fcx.finish(bcx, DebugLoc::None);
-
- llfn
}
+
fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
t: Ty<'tcx>,
struct_data: ValueRef)
trans_items,
reachable);
+ debug_dump(tcx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter());
+
// If the partitioning should produce a fixed count of codegen units, merge
// until that count is reached.
if let PartitioningStrategy::FixedUnitCount(count) = strategy {
merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name[..]);
+
+ debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
}
// In the next step, we use the inlining map to determine which addtional
// local functions the definition of which is marked with #[inline].
let post_inlining = place_inlined_translation_items(initial_partitioning,
inlining_map);
+
+ debug_dump(tcx, "POST INLINING:", post_inlining.0.iter());
+
post_inlining.0
}
NUMBERED_CODEGEN_UNIT_MARKER,
index)[..])
}
+
+fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ label: &str,
+ cgus: I)
+ where I: Iterator<Item=&'b CodegenUnit<'tcx>>,
+ 'tcx: 'a + 'b
+{
+ if cfg!(debug_assertions) {
+ debug!("{}", label);
+ for cgu in cgus {
+ debug!("CodegenUnit {}:", cgu.name);
+
+ for (trans_item, linkage) in &cgu.items {
+ debug!(" - {} [{:?}]", trans_item.to_string(tcx), linkage);
+ }
+
+ debug!("");
+ }
+ }
+}
use attributes;
use base;
-use context::{SharedCrateContext, CrateContext};
+use consts;
+use context::CrateContext;
use declare;
use glue::DropGlueKind;
use llvm;
use syntax::{attr,errors};
use syntax::parse::token;
use type_of;
-
+use glue;
+use abi::{Abi, FnType};
+use back::symbol_names;
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum TransItem<'tcx> {
impl<'a, 'tcx> TransItem<'tcx> {
+ pub 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);
+
+ match *self {
+ 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")
+ }
+ }
+ TransItem::Fn(instance) => {
+ base::trans_instance(&ccx, instance);
+ }
+ TransItem::DropGlue(dg) => {
+ glue::implement_drop_glue(&ccx, dg);
+ }
+ }
+
+ debug!("END IMPLEMENTING '{} ({})' in cgu {}",
+ self.to_string(ccx.tcx()),
+ self.to_raw_string(),
+ ccx.codegen_unit().name);
+ }
+
pub fn predefine(&self,
ccx: &CrateContext<'a, 'tcx>,
linkage: llvm::Linkage) {
+ debug!("BEGIN PREDEFINING '{} ({})' in cgu {}",
+ self.to_string(ccx.tcx()),
+ self.to_raw_string(),
+ ccx.codegen_unit().name);
+
match *self {
TransItem::Static(node_id) => {
TransItem::predefine_static(ccx, node_id, linkage);
TransItem::Fn(instance) => {
TransItem::predefine_fn(ccx, instance, linkage);
}
- _ => {
- // Not yet implemented
+ TransItem::DropGlue(dg) => {
+ TransItem::predefine_drop_glue(ccx, dg, linkage);
}
}
+
+ debug!("END PREDEFINING '{} ({})' in cgu {}",
+ self.to_string(ccx.tcx()),
+ self.to_raw_string(),
+ ccx.codegen_unit().name);
}
fn predefine_static(ccx: &CrateContext<'a, 'tcx>,
}) => {
let instance = Instance::mono(ccx.shared(), def_id);
let sym = instance.symbol_name(ccx.shared());
- debug!("making {}", sym);
+ debug!("symbol {}", sym);
let g = declare::define_global(ccx, &sym, llty).unwrap_or_else(|| {
ccx.sess().span_fatal(span,
fn predefine_fn(ccx: &CrateContext<'a, 'tcx>,
instance: Instance<'tcx>,
linkage: llvm::Linkage) {
- let unit = ccx.codegen_unit();
- debug!("predefine_fn[cg={}](instance={:?})", &unit.name[..], instance);
assert!(!instance.substs.types.needs_infer() &&
!instance.substs.types.has_param_types());
ref attrs, node: hir::ImplItemKind::Method(..), ..
}) => {
let symbol = instance.symbol_name(ccx.shared());
- let lldecl = declare::declare_fn(ccx, &symbol, mono_ty);
+ debug!("symbol {}", symbol);
- attributes::from_fn_attrs(ccx, attrs, lldecl);
+ let lldecl = declare::declare_fn(ccx, &symbol, mono_ty);
llvm::SetLinkage(lldecl, linkage);
+ attributes::from_fn_attrs(ccx, attrs, lldecl);
base::set_link_section(ccx, lldecl, attrs);
ccx.instances().borrow_mut().insert(instance, lldecl);
}
+ fn predefine_drop_glue(ccx: &CrateContext<'a, 'tcx>,
+ dg: glue::DropGlueKind<'tcx>,
+ linkage: llvm::Linkage) {
+ let tcx = ccx.tcx();
+ assert_eq!(dg.ty(), glue::get_drop_glue_type(tcx, dg.ty()));
+ let t = dg.ty();
+
+ let sig = ty::FnSig {
+ inputs: vec![tcx.mk_mut_ptr(tcx.types.i8)],
+ output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+ variadic: false,
+ };
+
+ // Create a FnType for fn(*mut i8) and substitute the real type in
+ // later - that prevents FnType from splitting fat pointers up.
+ let mut fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
+ fn_ty.args[0].original_ty = type_of::type_of(ccx, t).ptr_to();
+ let llfnty = fn_ty.llvm_type(ccx);
+
+ let prefix = match dg {
+ DropGlueKind::Ty(_) => "drop",
+ DropGlueKind::TyContents(_) => "drop_contents",
+ };
+
+ let symbol =
+ symbol_names::exported_name_from_type_and_prefix(ccx.shared(), t, prefix);
+ debug!(" symbol: {}", symbol);
+ assert!(declare::get_defined_value(ccx, &symbol).is_none());
+ let llfn = declare::declare_cfn(ccx, &symbol, llfnty);
+ attributes::set_frame_pointer_elimination(ccx, llfn);
+ llvm::SetLinkage(llfn, linkage);
+ ccx.drop_glues().borrow_mut().insert(dg, (llfn, fn_ty));
+ }
pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
match *self {
}
}
- pub fn to_string(&self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
- let tcx = scx.tcx();
+ pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
let hir_map = &tcx.map;
return match *self {
},
TransItem::Static(node_id) => {
let def_id = hir_map.local_def_id(node_id);
- let instance = Instance::mono(scx, def_id);
+ let instance = Instance::new(def_id,
+ tcx.mk_substs(subst::Substs::empty()));
to_string_internal(tcx, "static ", instance)
},
};
pub fn to_raw_string(&self) -> String {
match *self {
TransItem::DropGlue(dg) => {
- format!("DropGlue({})", dg.ty() as *const _ as usize)
+ let prefix = match dg {
+ DropGlueKind::Ty(_) => "Ty",
+ DropGlueKind::TyContents(_) => "TyContents",
+ };
+ format!("DropGlue({}: {})", prefix, dg.ty() as *const _ as usize)
}
TransItem::Fn(instance) => {
format!("Fn({:?}, {})",