about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorStuart Pernsteiner <spernsteiner@mozilla.com>2014-07-31 16:45:29 -0700
committerStuart Pernsteiner <spernsteiner@mozilla.com>2014-09-05 09:18:57 -0700
commite09bef810a95c82fa5de08872fccffdd5e0fe1e7 (patch)
treed5ef7a6a59de6b99c1588b340fad5c3921e0efbb /src
parentda9606247d5ddd0edebafaffd0367c541fbaee7e (diff)
downloadrust-e09bef810a95c82fa5de08872fccffdd5e0fe1e7.tar.gz
rust-e09bef810a95c82fa5de08872fccffdd5e0fe1e7.zip
avoid duplicate translation of monomorphizations, drop glue, and visit glue
Use a shared lookup table of previously-translated monomorphizations/glue
functions to avoid translating those functions in every compilation unit where
they're used.  Instead, the function will be translated in whichever
compilation unit uses it first, and the remaining compilation units will link
against that original definition.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/base.rs27
-rw-r--r--src/librustc/middle/trans/context.rs19
-rw-r--r--src/librustc/middle/trans/glue.rs55
-rw-r--r--src/librustc/middle/trans/meth.rs2
-rw-r--r--src/librustc/middle/trans/monomorphize.rs42
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,
                              &param_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
                 }
                 _ => {