@@ -89,13 +89,14 @@ use value::Value;
89
89
use Disr ;
90
90
use util:: common:: indenter;
91
91
use util:: sha2:: Sha256 ;
92
- use util:: nodemap:: { NodeMap , NodeSet } ;
92
+ use util:: nodemap:: { NodeMap , NodeSet , FnvHashSet } ;
93
93
94
94
use arena:: TypedArena ;
95
95
use libc:: c_uint;
96
96
use std:: ffi:: { CStr , CString } ;
97
+ use std:: borrow:: Cow ;
97
98
use std:: cell:: { Cell , RefCell } ;
98
- use std:: collections:: { HashMap , HashSet } ;
99
+ use std:: collections:: HashMap ;
99
100
use std:: ptr;
100
101
use std:: rc:: Rc ;
101
102
use std:: str;
@@ -2256,12 +2257,20 @@ fn write_metadata(cx: &SharedCrateContext,
2256
2257
2257
2258
/// Find any symbols that are defined in one compilation unit, but not declared
2258
2259
/// in any other compilation unit. Give these symbols internal linkage.
2259
- fn internalize_symbols ( cx : & CrateContextList , reachable : & HashSet < & str > ) {
2260
+ fn internalize_symbols < ' a , ' tcx > ( ccxs : & CrateContextList < ' a , ' tcx > ,
2261
+ symbol_map : & SymbolMap < ' tcx > ,
2262
+ reachable : & FnvHashSet < & str > ) {
2263
+ let scx = ccxs. shared ( ) ;
2264
+ let tcx = scx. tcx ( ) ;
2265
+
2266
+ // 'unsafe' because we are holding on to CStr's from the LLVM module within
2267
+ // this block.
2260
2268
unsafe {
2261
- let mut declared = HashSet :: new ( ) ;
2269
+ let mut referenced_somewhere = FnvHashSet ( ) ;
2262
2270
2263
- // Collect all external declarations in all compilation units.
2264
- for ccx in cx. iter ( ) {
2271
+ // Collect all symbols that need to stay externally visible because they
2272
+ // are referenced via a declaration in some other codegen unit.
2273
+ for ccx in ccxs. iter ( ) {
2265
2274
for val in iter_globals ( ccx. llmod ( ) ) . chain ( iter_functions ( ccx. llmod ( ) ) ) {
2266
2275
let linkage = llvm:: LLVMGetLinkage ( val) ;
2267
2276
// We only care about external declarations (not definitions)
@@ -2270,39 +2279,67 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
2270
2279
let is_decl = llvm:: LLVMIsDeclaration ( val) != 0 ;
2271
2280
2272
2281
if is_decl || is_available_externally {
2273
- let name = CStr :: from_ptr ( llvm:: LLVMGetValueName ( val) ) ;
2274
- declared . insert ( name ) ;
2282
+ let symbol_name = CStr :: from_ptr ( llvm:: LLVMGetValueName ( val) ) ;
2283
+ referenced_somewhere . insert ( symbol_name ) ;
2275
2284
}
2276
2285
}
2277
2286
}
2278
2287
2288
+ // Also collect all symbols for which we cannot adjust linkage, because
2289
+ // it is fixed by some directive in the source code (e.g. #[no_mangle]).
2290
+ let linkage_fixed_explicitly: FnvHashSet < _ > = scx
2291
+ . translation_items ( )
2292
+ . borrow ( )
2293
+ . iter ( )
2294
+ . cloned ( )
2295
+ . filter ( |trans_item|{
2296
+ let def_id = match * trans_item {
2297
+ TransItem :: DropGlue ( ..) => {
2298
+ return false
2299
+ } ,
2300
+ TransItem :: Fn ( ref instance) => {
2301
+ instance. def
2302
+ }
2303
+ TransItem :: Static ( node_id) => {
2304
+ tcx. map . local_def_id ( node_id)
2305
+ }
2306
+ } ;
2307
+
2308
+ trans_item. explicit_linkage ( tcx) . is_some ( ) ||
2309
+ attr:: contains_extern_indicator ( tcx. sess . diagnostic ( ) ,
2310
+ & tcx. get_attrs ( def_id) )
2311
+ } )
2312
+ . map ( |trans_item| symbol_map. get_or_compute ( scx, trans_item) )
2313
+ . collect ( ) ;
2314
+
2279
2315
// Examine each external definition. If the definition is not used in
2280
2316
// any other compilation unit, and is not reachable from other crates,
2281
2317
// then give it internal linkage.
2282
- for ccx in cx . iter ( ) {
2318
+ for ccx in ccxs . iter ( ) {
2283
2319
for val in iter_globals ( ccx. llmod ( ) ) . chain ( iter_functions ( ccx. llmod ( ) ) ) {
2284
2320
let linkage = llvm:: LLVMGetLinkage ( val) ;
2285
2321
2286
2322
let is_externally_visible = ( linkage == llvm:: ExternalLinkage as c_uint ) ||
2287
2323
( linkage == llvm:: LinkOnceODRLinkage as c_uint ) ||
2288
2324
( linkage == llvm:: WeakODRLinkage as c_uint ) ;
2289
- let is_definition = llvm:: LLVMIsDeclaration ( val) ! = 0 ;
2325
+ let is_definition = llvm:: LLVMIsDeclaration ( val) = = 0 ;
2290
2326
2291
2327
// If this is a definition (as opposed to just a declaration)
2292
2328
// and externally visible, check if we can internalize it
2293
2329
if is_definition && is_externally_visible {
2294
2330
let name_cstr = CStr :: from_ptr ( llvm:: LLVMGetValueName ( val) ) ;
2295
2331
let name_str = name_cstr. to_str ( ) . unwrap ( ) ;
2332
+ let name_cow = Cow :: Borrowed ( name_str) ;
2296
2333
2297
- let is_referenced_somewhere = declared. contains ( & name_cstr) ;
2298
- let is_reachable = reachable. contains ( name_str) ;
2334
+ let is_referenced_somewhere = referenced_somewhere. contains ( & name_cstr) ;
2335
+ let is_reachable = reachable. contains ( & name_str) ;
2336
+ let has_fixed_linkage = linkage_fixed_explicitly. contains ( & name_cow) ;
2299
2337
2300
- if !is_referenced_somewhere && !is_reachable {
2338
+ if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage {
2301
2339
llvm:: SetLinkage ( val, llvm:: InternalLinkage ) ;
2302
2340
llvm:: SetDLLStorageClass ( val, llvm:: DefaultStorageClass ) ;
2303
2341
llvm:: UnsetComdat ( val) ;
2304
2342
}
2305
-
2306
2343
}
2307
2344
}
2308
2345
}
@@ -2616,8 +2653,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
2616
2653
} ) ) ;
2617
2654
}
2618
2655
2619
- internalize_symbols ( & crate_context_list,
2620
- & reachable_symbols. iter ( ) . map ( |x| & x[ ..] ) . collect ( ) ) ;
2656
+ time ( shared_ccx. sess ( ) . time_passes ( ) , "internalize symbols" , || {
2657
+ internalize_symbols ( & crate_context_list,
2658
+ & symbol_map,
2659
+ & reachable_symbols. iter ( )
2660
+ . map ( |s| & s[ ..] )
2661
+ . collect ( ) )
2662
+ } ) ;
2621
2663
2622
2664
if sess. target . target . options . is_like_msvc &&
2623
2665
sess. crate_types . borrow ( ) . iter ( ) . any ( |ct| * ct == config:: CrateTypeRlib ) {
0 commit comments