diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/middle/trans/base.rs | 27 | ||||
| -rw-r--r-- | src/librustc/middle/trans/context.rs | 19 | ||||
| -rw-r--r-- | src/librustc/middle/trans/glue.rs | 55 | ||||
| -rw-r--r-- | src/librustc/middle/trans/meth.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/trans/monomorphize.rs | 42 |
5 files changed, 114 insertions, 31 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 81f76a82a54..e85e61d8291 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2124,11 +2124,24 @@ impl<'a> Visitor<()> for TransItemVisitor<'a> { } } -pub fn update_linkage(ccx: &CrateContext, llval: ValueRef, id: ast::NodeId) { - if ccx.reachable().contains(&id) || ccx.sess().opts.cg.codegen_units > 1 { - llvm::SetLinkage(llval, llvm::ExternalLinkage); - } else { - llvm::SetLinkage(llval, llvm::InternalLinkage); +/// 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>) { + match id { + Some(id) if ccx.reachable().contains(&id) => { + llvm::SetLinkage(llval, llvm::ExternalLinkage); + }, + _ => { + // `id` does not refer to an item in `ccx.reachable`. + if ccx.sess().opts.cg.codegen_units > 1 { + llvm::SetLinkage(llval, llvm::ExternalLinkage); + } else { + llvm::SetLinkage(llval, llvm::InternalLinkage); + } + }, } } @@ -2157,7 +2170,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { item.id, item.attrs.as_slice()); } - update_linkage(ccx, llfn, item.id); + update_linkage(ccx, llfn, Some(item.id)); } // Be sure to travel more than just one layer deep to catch nested @@ -2185,7 +2198,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { consts::trans_const(ccx, m, item.id); let g = get_item_val(ccx, item.id); - update_linkage(ccx, g, item.id); + update_linkage(ccx, g, Some(item.id)); // Do static_assert checking. It can't really be done much earlier // because we need to get the value of the bool out of LLVM diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 4184c49b905..64722208aa5 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -72,6 +72,10 @@ pub struct SharedCrateContext { symbol_hasher: RefCell<Sha256>, tcx: ty::ctxt, stats: Stats, + + available_monomorphizations: RefCell<HashSet<String>>, + available_drop_glues: RefCell<HashMap<ty::t, String>>, + available_visit_glues: RefCell<HashMap<ty::t, String>>, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -233,6 +237,9 @@ impl SharedCrateContext { llvm_insns: RefCell::new(HashMap::new()), fn_stats: RefCell::new(Vec::new()), }, + available_monomorphizations: RefCell::new(HashSet::new()), + available_drop_glues: RefCell::new(HashMap::new()), + available_visit_glues: RefCell::new(HashMap::new()), }; for i in range(0, local_count) { @@ -612,6 +619,18 @@ impl<'b> CrateContext<'b> { &self.shared.stats } + pub fn available_monomorphizations<'a>(&'a self) -> &'a RefCell<HashSet<String>> { + &self.shared.available_monomorphizations + } + + pub fn available_drop_glues<'a>(&'a self) -> &'a RefCell<HashMap<ty::t, String>> { + &self.shared.available_drop_glues + } + + pub fn available_visit_glues<'a>(&'a self) -> &'a RefCell<HashMap<ty::t, String>> { + &self.shared.available_visit_glues + } + pub fn int_type(&self) -> Type { self.local.int_type } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 915c171b318..e0ef867c23e 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -171,11 +171,30 @@ pub fn get_drop_glue(ccx: &CrateContext, t: ty::t) -> ValueRef { }; let llfnty = Type::glue_fn(ccx, llty); - let glue = declare_generic_glue(ccx, t, llfnty, "drop"); + + let (glue, new_sym) = match ccx.available_drop_glues().borrow().find(&t) { + Some(old_sym) => { + let glue = decl_cdecl_fn(ccx, old_sym.as_slice(), llfnty, ty::mk_nil()); + (glue, None) + }, + None => { + let (sym, glue) = declare_generic_glue(ccx, t, llfnty, "drop"); + (glue, Some(sym)) + }, + }; ccx.drop_glues().borrow_mut().insert(t, glue); - make_generic_glue(ccx, t, glue, make_drop_glue, "drop"); + // To avoid infinite recursion, don't `make_drop_glue` until after we've + // added the entry to the `drop_glues` cache. + match new_sym { + Some(sym) => { + ccx.available_drop_glues().borrow_mut().insert(t, sym); + // We're creating a new drop glue, so also generate a body. + make_generic_glue(ccx, t, glue, make_drop_glue, "drop"); + }, + None => {}, + } glue } @@ -189,9 +208,28 @@ pub fn lazily_emit_visit_glue(ccx: &CrateContext, ti: &tydesc_info) -> ValueRef Some(visit_glue) => visit_glue, None => { debug!("+++ lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_string(ccx.tcx(), ti.ty)); - let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "visit"); + + let (glue_fn, new_sym) = match ccx.available_visit_glues().borrow().find(&ti.ty) { + Some(old_sym) => { + let glue_fn = decl_cdecl_fn(ccx, old_sym.as_slice(), llfnty, ty::mk_nil()); + (glue_fn, None) + }, + None => { + let (sym, glue_fn) = declare_generic_glue(ccx, ti.ty, llfnty, "visit"); + (glue_fn, Some(sym)) + }, + }; + ti.visit_glue.set(Some(glue_fn)); - make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit"); + + match new_sym { + Some(sym) => { + ccx.available_visit_glues().borrow_mut().insert(ti.ty, sym); + make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit"); + }, + None => {}, + } + debug!("--- lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_string(ccx.tcx(), ti.ty)); glue_fn } @@ -602,15 +640,15 @@ pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> tydesc_info { } fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type, - name: &str) -> ValueRef { + name: &str) -> (String, ValueRef) { let _icx = push_ctxt("declare_generic_glue"); let fn_nm = mangle_internal_name_by_type_and_seq( ccx, t, format!("glue_{}", name).as_slice()); let llfn = decl_cdecl_fn(ccx, fn_nm.as_slice(), llfnty, ty::mk_nil()); - note_unique_llvm_symbol(ccx, fn_nm); - return llfn; + note_unique_llvm_symbol(ccx, fn_nm.clone()); + return (fn_nm, llfn); } fn make_generic_glue(ccx: &CrateContext, @@ -631,7 +669,8 @@ fn make_generic_glue(ccx: &CrateContext, let bcx = init_function(&fcx, false, ty::mk_nil()); - llvm::SetLinkage(llfn, llvm::InternalLinkage); + update_linkage(ccx, llfn, None); + ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1u); // All glue functions take values passed *by alias*; this is a // requirement since in many contexts glue is invoked indirectly and diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 92d8db0e4ea..f1101060d97 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -85,7 +85,7 @@ pub fn trans_impl(ccx: &CrateContext, ¶m_substs::empty(), method.id, []); - update_linkage(ccx, llfn, method.id); + update_linkage(ccx, llfn, Some(method.id)); } let mut v = TransItemVisitor { ccx: ccx, diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 16d1ad810b7..1dd0de3904d 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -159,14 +159,18 @@ pub fn monomorphic_fn(ccx: &CrateContext, .. } => { let d = mk_lldecl(abi); + base::update_linkage(ccx, d, None); set_llvm_fn_attrs(i.attrs.as_slice(), d); - if abi != abi::Rust { - foreign::trans_rust_fn_with_foreign_abi( - ccx, &**decl, &**body, [], d, &psubsts, fn_id.node, - Some(hash.as_slice())); - } else { - trans_fn(ccx, &**decl, &**body, d, &psubsts, fn_id.node, []); + if !ccx.available_monomorphizations().borrow().contains(&s) { + ccx.available_monomorphizations().borrow_mut().insert(s.clone()); + if abi != abi::Rust { + foreign::trans_rust_fn_with_foreign_abi( + ccx, &**decl, &**body, [], d, &psubsts, fn_id.node, + Some(hash.as_slice())); + } else { + trans_fn(ccx, &**decl, &**body, d, &psubsts, fn_id.node, []); + } } d @@ -201,14 +205,18 @@ pub fn monomorphic_fn(ccx: &CrateContext, match *ii { ast::MethodImplItem(mth) => { let d = mk_lldecl(abi::Rust); + base::update_linkage(ccx, d, None); set_llvm_fn_attrs(mth.attrs.as_slice(), d); - trans_fn(ccx, - &*mth.pe_fn_decl(), - &*mth.pe_body(), - d, - &psubsts, - mth.id, - []); + if !ccx.available_monomorphizations().borrow().contains(&s) { + ccx.available_monomorphizations().borrow_mut().insert(s.clone()); + trans_fn(ccx, + &*mth.pe_fn_decl(), + &*mth.pe_body(), + d, + &psubsts, + mth.id, + []); + } d } } @@ -217,9 +225,13 @@ pub fn monomorphic_fn(ccx: &CrateContext, match *method { ast::ProvidedMethod(mth) => { let d = mk_lldecl(abi::Rust); + base::update_linkage(ccx, d, None); set_llvm_fn_attrs(mth.attrs.as_slice(), d); - trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d, - &psubsts, mth.id, []); + if !ccx.available_monomorphizations().borrow().contains(&s) { + ccx.available_monomorphizations().borrow_mut().insert(s.clone()); + trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d, + &psubsts, mth.id, []); + } d } _ => { |
