Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
2f07eb32
R
Rust
项目概览
int
/
Rust
接近 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
2f07eb32
编写于
7月 12, 2017
作者:
M
Michael Woerister
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
trans: Internalize symbols at the trans-item level, without relying on LLVM.
上级
1ebfab51
变更
11
显示空白变更内容
内联
并排
Showing
11 changed file
with
383 addition
and
265 deletion
+383
-265
src/librustc_trans/back/linker.rs
src/librustc_trans/back/linker.rs
+3
-5
src/librustc_trans/back/lto.rs
src/librustc_trans/back/lto.rs
+1
-1
src/librustc_trans/back/symbol_export.rs
src/librustc_trans/back/symbol_export.rs
+72
-40
src/librustc_trans/base.rs
src/librustc_trans/base.rs
+27
-162
src/librustc_trans/callee.rs
src/librustc_trans/callee.rs
+18
-4
src/librustc_trans/collector.rs
src/librustc_trans/collector.rs
+4
-6
src/librustc_trans/consts.rs
src/librustc_trans/consts.rs
+14
-0
src/librustc_trans/context.rs
src/librustc_trans/context.rs
+24
-9
src/librustc_trans/debuginfo/utils.rs
src/librustc_trans/debuginfo/utils.rs
+1
-1
src/librustc_trans/partitioning.rs
src/librustc_trans/partitioning.rs
+205
-33
src/librustc_trans/trans_item.rs
src/librustc_trans/trans_item.rs
+14
-4
未找到文件。
src/librustc_trans/back/linker.rs
浏览文件 @
2f07eb32
...
...
@@ -19,7 +19,7 @@
use
context
::
SharedCrateContext
;
use
back
::
archive
;
use
back
::
symbol_export
::
{
self
,
ExportedSymbols
}
;
use
back
::
symbol_export
::
ExportedSymbols
;
use
rustc
::
middle
::
dependency_format
::
Linkage
;
use
rustc
::
hir
::
def_id
::{
LOCAL_CRATE
,
CrateNum
};
use
rustc_back
::
LinkerFlavor
;
...
...
@@ -687,10 +687,8 @@ fn exported_symbols(scx: &SharedCrateContext,
exported_symbols
:
&
ExportedSymbols
,
crate_type
:
CrateType
)
->
Vec
<
String
>
{
let
export_threshold
=
symbol_export
::
crate_export_threshold
(
crate_type
);
let
mut
symbols
=
Vec
::
new
();
exported_symbols
.for_each_exported_symbol
(
LOCAL_CRATE
,
export_threshold
,
|
name
,
_
|
{
exported_symbols
.for_each_exported_symbol
(
LOCAL_CRATE
,
|
name
,
_
,
_
|
{
symbols
.push
(
name
.to_owned
());
});
...
...
@@ -702,7 +700,7 @@ fn exported_symbols(scx: &SharedCrateContext,
// For each dependency that we are linking to statically ...
if
*
dep_format
==
Linkage
::
Static
{
// ... we add its symbol list to our export list.
exported_symbols
.for_each_exported_symbol
(
cnum
,
export_threshold
,
|
name
,
_
|
{
exported_symbols
.for_each_exported_symbol
(
cnum
,
|
name
,
_
,
_
|
{
symbols
.push
(
name
.to_owned
());
})
}
...
...
src/librustc_trans/back/lto.rs
浏览文件 @
2f07eb32
...
...
@@ -66,7 +66,7 @@ pub fn run(cgcx: &CodegenContext,
let
export_threshold
=
symbol_export
::
crates_export_threshold
(
&
cgcx
.crate_types
);
let
symbol_filter
=
&
|
&
(
ref
name
,
level
):
&
(
String
,
_
)|
{
let
symbol_filter
=
&
|
&
(
ref
name
,
_
,
level
):
&
(
String
,
_
,
_
)|
{
if
symbol_export
::
is_below_threshold
(
level
,
export_threshold
)
{
let
mut
bytes
=
Vec
::
with_capacity
(
name
.len
()
+
1
);
bytes
.extend
(
name
.bytes
());
...
...
src/librustc_trans/back/symbol_export.rs
浏览文件 @
2f07eb32
...
...
@@ -8,10 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use
context
::
SharedCrateContext
;
use
monomorphize
::
Instance
;
use
rustc
::
util
::
nodemap
::
FxHashMap
;
use
rustc
::
hir
::
def_id
::{
DefId
,
CrateNum
,
LOCAL_CRATE
};
use
rustc
::
util
::
nodemap
::
{
FxHashMap
,
NodeSet
}
;
use
rustc
::
hir
::
def_id
::{
DefId
,
CrateNum
,
LOCAL_CRATE
,
INVALID_CRATE
,
CRATE_DEF_INDEX
};
use
rustc
::
session
::
config
;
use
rustc
::
ty
::
TyCtxt
;
use
syntax
::
attr
;
...
...
@@ -28,59 +27,87 @@ pub enum SymbolExportLevel {
}
/// The set of symbols exported from each crate in the crate graph.
#[derive(Debug)]
pub
struct
ExportedSymbols
{
exports
:
FxHashMap
<
CrateNum
,
Vec
<
(
String
,
SymbolExportLevel
)
>>
,
pub
export_threshold
:
SymbolExportLevel
,
exports
:
FxHashMap
<
CrateNum
,
Vec
<
(
String
,
DefId
,
SymbolExportLevel
)
>>
,
local_exports
:
NodeSet
,
}
impl
ExportedSymbols
{
pub
fn
empty
()
->
ExportedSymbols
{
ExportedSymbols
{
export_threshold
:
SymbolExportLevel
::
C
,
exports
:
FxHashMap
(),
local_exports
:
NodeSet
(),
}
}
pub
fn
compute
<
'a
,
'tcx
>
(
scx
:
&
SharedCrateContext
<
'a
,
'tcx
>
)
->
ExportedSymbols
{
let
mut
local_crate
:
Vec
<
_
>
=
scx
.exported_symbols
()
pub
fn
compute
<
'a
,
'tcx
>
(
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
local_exported_symbols
:
&
NodeSet
)
->
ExportedSymbols
{
let
export_threshold
=
crates_export_threshold
(
&
tcx
.sess.crate_types
.borrow
());
let
mut
local_crate
:
Vec
<
_
>
=
local_exported_symbols
.iter
()
.map
(|
&
node_id
|
{
scx
.tcx
()
.hir
.local_def_id
(
node_id
)
tcx
.hir
.local_def_id
(
node_id
)
})
.map
(|
def_id
|
{
let
name
=
scx
.tcx
()
.symbol_name
(
Instance
::
mono
(
scx
.tcx
()
,
def_id
));
let
export_level
=
export_level
(
s
cx
,
def_id
);
let
name
=
tcx
.symbol_name
(
Instance
::
mono
(
tcx
,
def_id
));
let
export_level
=
export_level
(
t
cx
,
def_id
);
debug!
(
"EXPORTED SYMBOL (local): {} ({:?})"
,
name
,
export_level
);
(
str
::
to_owned
(
&
name
),
export_level
)
(
str
::
to_owned
(
&
name
),
def_id
,
export_level
)
})
.collect
();
if
scx
.sess
()
.entry_fn
.borrow
()
.is_some
()
{
local_crate
.push
((
"main"
.to_string
(),
SymbolExportLevel
::
C
));
let
mut
local_exports
=
local_crate
.iter
()
.filter_map
(|
&
(
_
,
def_id
,
level
)|
{
if
is_below_threshold
(
level
,
export_threshold
)
{
tcx
.hir
.as_local_node_id
(
def_id
)
}
else
{
None
}
})
.collect
::
<
NodeSet
>
();
const
INVALID_DEF_ID
:
DefId
=
DefId
{
krate
:
INVALID_CRATE
,
index
:
CRATE_DEF_INDEX
,
};
if
let
Some
(
_
)
=
*
tcx
.sess.entry_fn
.borrow
()
{
local_crate
.push
((
"main"
.to_string
(),
INVALID_DEF_ID
,
SymbolExportLevel
::
C
));
}
if
let
Some
(
id
)
=
scx
.sess
()
.derive_registrar_fn
.get
()
{
let
def_id
=
scx
.tcx
()
.hir
.local_def_id
(
id
);
if
let
Some
(
id
)
=
tcx
.sess
.derive_registrar_fn
.get
()
{
let
def_id
=
tcx
.hir
.local_def_id
(
id
);
let
idx
=
def_id
.index
;
let
disambiguator
=
scx
.sess
()
.local_crate_disambiguator
();
let
registrar
=
scx
.sess
()
.generate_derive_registrar_symbol
(
disambiguator
,
idx
);
local_crate
.push
((
registrar
,
SymbolExportLevel
::
C
));
let
disambiguator
=
tcx
.sess
.local_crate_disambiguator
();
let
registrar
=
tcx
.sess
.generate_derive_registrar_symbol
(
disambiguator
,
idx
);
local_crate
.push
((
registrar
,
def_id
,
SymbolExportLevel
::
C
));
local_exports
.insert
(
id
);
}
if
scx
.sess
()
.crate_types
.borrow
()
.contains
(
&
config
::
CrateTypeDylib
)
{
local_crate
.push
((
metadata_symbol_name
(
scx
.tcx
()),
if
tcx
.sess.crate_types
.borrow
()
.contains
(
&
config
::
CrateTypeDylib
)
{
local_crate
.push
((
metadata_symbol_name
(
tcx
),
INVALID_DEF_ID
,
SymbolExportLevel
::
Rust
));
}
let
mut
exports
=
FxHashMap
();
exports
.insert
(
LOCAL_CRATE
,
local_crate
);
for
cnum
in
scx
.sess
()
.cstore
.crates
()
{
for
cnum
in
tcx
.sess
.cstore
.crates
()
{
debug_assert!
(
cnum
!=
LOCAL_CRATE
);
// If this crate is a plugin and/or a custom derive crate, then
// we're not even going to link those in so we skip those crates.
if
scx
.sess
()
.cstore
.plugin_registrar_fn
(
cnum
)
.is_some
()
||
scx
.sess
()
.cstore
.derive_registrar_fn
(
cnum
)
.is_some
()
{
if
tcx
.sess
.cstore
.plugin_registrar_fn
(
cnum
)
.is_some
()
||
tcx
.sess
.cstore
.derive_registrar_fn
(
cnum
)
.is_some
()
{
continue
;
}
...
...
@@ -92,16 +119,16 @@ pub fn compute<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) -> ExportedSymbols
// Down below we'll hardwire all of the symbols to the `Rust` export
// level instead.
let
special_runtime_crate
=
scx
.tcx
()
.is_panic_runtime
(
cnum
.as_def_id
())
||
scx
.sess
()
.cstore
.is_compiler_builtins
(
cnum
);
tcx
.is_panic_runtime
(
cnum
.as_def_id
())
||
tcx
.sess
.cstore
.is_compiler_builtins
(
cnum
);
let
crate_exports
=
s
cx
.sess
()
let
crate_exports
=
t
cx
.sess
.cstore
.exported_symbols
(
cnum
)
.iter
()
.map
(|
&
def_id
|
{
let
name
=
scx
.tcx
()
.symbol_name
(
Instance
::
mono
(
scx
.tcx
()
,
def_id
));
let
name
=
tcx
.symbol_name
(
Instance
::
mono
(
tcx
,
def_id
));
let
export_level
=
if
special_runtime_crate
{
// We can probably do better here by just ensuring that
// it has hidden visibility rather than public
...
...
@@ -118,10 +145,10 @@ pub fn compute<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) -> ExportedSymbols
SymbolExportLevel
::
Rust
}
}
else
{
export_level
(
s
cx
,
def_id
)
export_level
(
t
cx
,
def_id
)
};
debug!
(
"EXPORTED SYMBOL (re-export): {} ({:?})"
,
name
,
export_level
);
(
str
::
to_owned
(
&
name
),
export_level
)
(
str
::
to_owned
(
&
name
),
def_id
,
export_level
)
})
.collect
();
...
...
@@ -129,14 +156,16 @@ pub fn compute<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) -> ExportedSymbols
}
return
ExportedSymbols
{
exports
:
exports
export_threshold
,
exports
,
local_exports
,
};
fn
export_level
(
scx
:
&
SharedCrateConte
xt
,
fn
export_level
(
tcx
:
TyCt
xt
,
sym_def_id
:
DefId
)
->
SymbolExportLevel
{
let
attrs
=
scx
.tcx
()
.get_attrs
(
sym_def_id
);
if
attr
::
contains_extern_indicator
(
scx
.sess
()
.diagnostic
(),
&
attrs
)
{
let
attrs
=
tcx
.get_attrs
(
sym_def_id
);
if
attr
::
contains_extern_indicator
(
tcx
.sess
.diagnostic
(),
&
attrs
)
{
SymbolExportLevel
::
C
}
else
{
SymbolExportLevel
::
Rust
...
...
@@ -144,9 +173,13 @@ fn export_level(scx: &SharedCrateContext,
}
}
pub
fn
local_exports
(
&
self
)
->
&
NodeSet
{
&
self
.local_exports
}
pub
fn
exported_symbols
(
&
self
,
cnum
:
CrateNum
)
->
&
[(
String
,
SymbolExportLevel
)]
{
->
&
[(
String
,
DefId
,
SymbolExportLevel
)]
{
match
self
.exports
.get
(
&
cnum
)
{
Some
(
exports
)
=>
exports
,
None
=>
&
[]
...
...
@@ -155,13 +188,12 @@ pub fn exported_symbols(&self,
pub
fn
for_each_exported_symbol
<
F
>
(
&
self
,
cnum
:
CrateNum
,
export_threshold
:
SymbolExportLevel
,
mut
f
:
F
)
where
F
:
FnMut
(
&
str
,
SymbolExportLevel
)
where
F
:
FnMut
(
&
str
,
DefId
,
SymbolExportLevel
)
{
for
&
(
ref
name
,
export_level
)
in
self
.exported_symbols
(
cnum
)
{
if
is_below_threshold
(
export_level
,
export_threshold
)
{
f
(
&
name
,
export_level
)
for
&
(
ref
name
,
def_id
,
export_level
)
in
self
.exported_symbols
(
cnum
)
{
if
is_below_threshold
(
export_level
,
self
.
export_threshold
)
{
f
(
&
name
,
def_id
,
export_level
)
}
}
}
...
...
src/librustc_trans/base.rs
浏览文件 @
2f07eb32
...
...
@@ -77,6 +77,7 @@
use
libc
::
c_uint
;
use
std
::
ffi
::{
CStr
,
CString
};
use
std
::
str
;
use
std
::
sync
::
Arc
;
use
std
::
i32
;
use
syntax_pos
::
Span
;
use
syntax
::
attr
;
...
...
@@ -796,131 +797,6 @@ enum MetadataKind {
return
(
metadata_llcx
,
metadata_llmod
,
metadata
);
}
/// Find any symbols that are defined in one compilation unit, but not declared
/// in any other compilation unit. Give these symbols internal linkage.
fn
internalize_symbols
<
'a
,
'tcx
>
(
sess
:
&
Session
,
scx
:
&
SharedCrateContext
<
'a
,
'tcx
>
,
translation_items
:
&
FxHashSet
<
TransItem
<
'tcx
>>
,
llvm_modules
:
&
[
ModuleLlvm
],
exported_symbols
:
&
ExportedSymbols
)
{
let
export_threshold
=
symbol_export
::
crates_export_threshold
(
&
sess
.crate_types
.borrow
());
let
exported_symbols
=
exported_symbols
.exported_symbols
(
LOCAL_CRATE
)
.iter
()
.filter
(|
&&
(
_
,
export_level
)|
{
symbol_export
::
is_below_threshold
(
export_level
,
export_threshold
)
})
.map
(|
&
(
ref
name
,
_
)|
&
name
[
..
])
.collect
::
<
FxHashSet
<&
str
>>
();
let
tcx
=
scx
.tcx
();
let
incr_comp
=
sess
.opts.debugging_opts.incremental
.is_some
();
// 'unsafe' because we are holding on to CStr's from the LLVM module within
// this block.
unsafe
{
let
mut
referenced_somewhere
=
FxHashSet
();
// Collect all symbols that need to stay externally visible because they
// are referenced via a declaration in some other codegen unit. In
// incremental compilation, we don't need to collect. See below for more
// information.
if
!
incr_comp
{
for
ll
in
llvm_modules
{
for
val
in
iter_globals
(
ll
.llmod
)
.chain
(
iter_functions
(
ll
.llmod
))
{
let
linkage
=
llvm
::
LLVMRustGetLinkage
(
val
);
// We only care about external declarations (not definitions)
// and available_externally definitions.
let
is_available_externally
=
linkage
==
llvm
::
Linkage
::
AvailableExternallyLinkage
;
let
is_decl
=
llvm
::
LLVMIsDeclaration
(
val
)
==
llvm
::
True
;
if
is_decl
||
is_available_externally
{
let
symbol_name
=
CStr
::
from_ptr
(
llvm
::
LLVMGetValueName
(
val
));
referenced_somewhere
.insert
(
symbol_name
);
}
}
}
}
// Also collect all symbols for which we cannot adjust linkage, because
// it is fixed by some directive in the source code.
let
(
locally_defined_symbols
,
linkage_fixed_explicitly
)
=
{
let
mut
locally_defined_symbols
=
FxHashSet
();
let
mut
linkage_fixed_explicitly
=
FxHashSet
();
for
trans_item
in
translation_items
{
let
symbol_name
=
str
::
to_owned
(
&
trans_item
.symbol_name
(
tcx
));
if
trans_item
.explicit_linkage
(
tcx
)
.is_some
()
{
linkage_fixed_explicitly
.insert
(
symbol_name
.clone
());
}
locally_defined_symbols
.insert
(
symbol_name
);
}
(
locally_defined_symbols
,
linkage_fixed_explicitly
)
};
// Examine each external definition. If the definition is not used in
// any other compilation unit, and is not reachable from other crates,
// then give it internal linkage.
for
ll
in
llvm_modules
{
for
val
in
iter_globals
(
ll
.llmod
)
.chain
(
iter_functions
(
ll
.llmod
))
{
let
linkage
=
llvm
::
LLVMRustGetLinkage
(
val
);
let
is_externally_visible
=
(
linkage
==
llvm
::
Linkage
::
ExternalLinkage
)
||
(
linkage
==
llvm
::
Linkage
::
LinkOnceODRLinkage
)
||
(
linkage
==
llvm
::
Linkage
::
WeakODRLinkage
);
if
!
is_externally_visible
{
// This symbol is not visible outside of its codegen unit,
// so there is nothing to do for it.
continue
;
}
let
name_cstr
=
CStr
::
from_ptr
(
llvm
::
LLVMGetValueName
(
val
));
let
name_str
=
name_cstr
.to_str
()
.unwrap
();
if
exported_symbols
.contains
(
&
name_str
)
{
// This symbol is explicitly exported, so we can't
// mark it as internal or hidden.
continue
;
}
let
is_declaration
=
llvm
::
LLVMIsDeclaration
(
val
)
==
llvm
::
True
;
if
is_declaration
{
if
locally_defined_symbols
.contains
(
name_str
)
{
// Only mark declarations from the current crate as hidden.
// Otherwise we would mark things as hidden that are
// imported from other crates or native libraries.
llvm
::
LLVMRustSetVisibility
(
val
,
llvm
::
Visibility
::
Hidden
);
}
}
else
{
let
has_fixed_linkage
=
linkage_fixed_explicitly
.contains
(
name_str
);
if
!
has_fixed_linkage
{
// In incremental compilation mode, we can't be sure that
// we saw all references because we don't know what's in
// cached compilation units, so we always assume that the
// given item has been referenced.
if
incr_comp
||
referenced_somewhere
.contains
(
&
name_cstr
)
{
llvm
::
LLVMRustSetVisibility
(
val
,
llvm
::
Visibility
::
Hidden
);
}
else
{
llvm
::
LLVMRustSetLinkage
(
val
,
llvm
::
Linkage
::
InternalLinkage
);
}
llvm
::
LLVMSetDLLStorageClass
(
val
,
llvm
::
DLLStorageClass
::
Default
);
llvm
::
UnsetComdat
(
val
);
}
}
}
}
}
}
// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
// This is required to satisfy `dllimport` references to static data in .rlibs
// when using MSVC linker. We do this only for data, as linker can fix up
...
...
@@ -992,15 +868,6 @@ fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter {
}
}
fn
iter_functions
(
llmod
:
llvm
::
ModuleRef
)
->
ValueIter
{
unsafe
{
ValueIter
{
cur
:
llvm
::
LLVMGetFirstFunction
(
llmod
),
step
:
llvm
::
LLVMGetNextFunction
,
}
}
}
/// The context provided lists a set of reachable ids as calculated by
/// middle::reachable, but this contains far more ids and symbols than we're
/// actually exposing from the object file. This function will filter the set in
...
...
@@ -1063,20 +930,19 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let
krate
=
tcx
.hir
.krate
();
let
ty
::
CrateAnalysis
{
reachable
,
..
}
=
analysis
;
let
exported_symbols
=
find_exported_symbols
(
tcx
,
&
reachable
);
let
check_overflow
=
tcx
.sess
.overflow_checks
();
let
link_meta
=
link
::
build_link_meta
(
incremental_hashes_map
);
let
exported_symbol_node_ids
=
find_exported_symbols
(
tcx
,
&
reachable
);
let
shared_ccx
=
SharedCrateContext
::
new
(
tcx
,
exported_symbols
,
check_overflow
,
output_filenames
);
// Translate the metadata.
let
(
metadata_llcx
,
metadata_llmod
,
metadata
)
=
time
(
tcx
.sess
.time_passes
(),
"write metadata"
,
||
{
write_metadata
(
tcx
,
&
link_meta
,
shared_ccx
.exported_symbols
()
)
write_metadata
(
tcx
,
&
link_meta
,
&
exported_symbol_node_ids
)
});
let
metadata_module
=
ModuleTranslation
{
...
...
@@ -1090,7 +956,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let
no_builtins
=
attr
::
contains_name
(
&
krate
.attrs
,
"no_builtins"
);
// Skip crate items and just output metadata in -Z no-trans mode.
if
tcx
.sess.opts.debugging_opts.no_trans
||
!
tcx
.sess.opts.output_types
.should_trans
()
{
...
...
@@ -1110,10 +975,15 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};
}
let
exported_symbols
=
Arc
::
new
(
ExportedSymbols
::
compute
(
tcx
,
&
exported_symbol_node_ids
));
// Run the translation item collector and partition the collected items into
// codegen units.
let
(
translation_items
,
codegen_units
)
=
collect_and_partition_translation_items
(
&
shared_ccx
);
collect_and_partition_translation_items
(
&
shared_ccx
,
&
exported_symbols
);
let
translation_items
=
Arc
::
new
(
translation_items
);
let
mut
all_stats
=
Stats
::
default
();
let
modules
:
Vec
<
ModuleTranslation
>
=
codegen_units
...
...
@@ -1123,7 +993,9 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let
((
stats
,
module
),
_
)
=
tcx
.dep_graph
.with_task
(
dep_node
,
AssertDepGraphSafe
(
&
shared_ccx
),
AssertDepGraphSafe
(
cgu
),
AssertDepGraphSafe
((
cgu
,
translation_items
.clone
(),
exported_symbols
.clone
())),
module_translation
);
all_stats
.extend
(
stats
);
module
...
...
@@ -1132,16 +1004,18 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn
module_translation
<
'a
,
'tcx
>
(
scx
:
AssertDepGraphSafe
<&
SharedCrateContext
<
'a
,
'tcx
>>
,
args
:
AssertDepGraphSafe
<
CodegenUnit
<
'tcx
>>
)
args
:
AssertDepGraphSafe
<
(
CodegenUnit
<
'tcx
>
,
Arc
<
FxHashSet
<
TransItem
<
'tcx
>>>
,
Arc
<
ExportedSymbols
>
)
>
)
->
(
Stats
,
ModuleTranslation
)
{
// FIXME(#40304): We ought to be using the id as a key and some queries, I think.
let
AssertDepGraphSafe
(
scx
)
=
scx
;
let
AssertDepGraphSafe
(
cgu
)
=
args
;
let
AssertDepGraphSafe
(
(
cgu
,
crate_trans_items
,
exported_symbols
)
)
=
args
;
let
cgu_name
=
String
::
from
(
cgu
.name
());
let
cgu_id
=
cgu
.work_product_id
();
let
symbol_name_hash
=
cgu
.compute_symbol_name_hash
(
scx
);
let
symbol_name_hash
=
cgu
.compute_symbol_name_hash
(
scx
,
&
exported_symbols
);
// Check whether there is a previous work-product we can
// re-use. Not only must the file exist, and the inputs not
...
...
@@ -1176,13 +1050,13 @@ fn module_translation<'a, 'tcx>(
}
// Instantiate translation items without filling out definitions yet...
let
lcx
=
LocalCrateContext
::
new
(
scx
,
cgu
);
let
lcx
=
LocalCrateContext
::
new
(
scx
,
cgu
,
crate_trans_items
,
exported_symbols
);
let
module
=
{
let
ccx
=
CrateContext
::
new
(
scx
,
&
lcx
);
let
trans_items
=
ccx
.codegen_unit
()
.items_in_deterministic_order
(
ccx
.tcx
());
for
&
(
trans_item
,
linkage
)
in
&
trans_items
{
trans_item
.predefine
(
&
ccx
,
linkage
);
for
&
(
trans_item
,
(
linkage
,
visibility
)
)
in
&
trans_items
{
trans_item
.predefine
(
&
ccx
,
linkage
,
visibility
);
}
// ... and now that we have everything pre-defined, fill out those definitions.
...
...
@@ -1272,8 +1146,6 @@ fn module_translation<'a, 'tcx>(
let
sess
=
shared_ccx
.sess
();
let
exported_symbols
=
ExportedSymbols
::
compute
(
&
shared_ccx
);
// Get the list of llvm modules we created. We'll do a few wacky
// transforms on them now.
...
...
@@ -1285,16 +1157,6 @@ fn module_translation<'a, 'tcx>(
})
.collect
();
// Now that we have all symbols that are exported from the CGUs of this
// crate, we can run the `internalize_symbols` pass.
time
(
shared_ccx
.sess
()
.time_passes
(),
"internalize symbols"
,
||
{
internalize_symbols
(
sess
,
&
shared_ccx
,
&
translation_items
,
&
llvm_modules
,
&
exported_symbols
);
});
if
sess
.target.target.options.is_like_msvc
&&
sess
.crate_types
.borrow
()
.iter
()
.any
(|
ct
|
*
ct
==
config
::
CrateTypeRlib
)
{
create_imps
(
sess
,
&
llvm_modules
);
...
...
@@ -1355,7 +1217,8 @@ fn module_translation<'a, 'tcx>(
allocator_module
:
allocator_module
,
link
:
link_meta
,
metadata
:
metadata
,
exported_symbols
:
exported_symbols
,
exported_symbols
:
Arc
::
try_unwrap
(
exported_symbols
)
.expect
(
"There's still a reference to exported_symbols?"
),
no_builtins
:
no_builtins
,
linker_info
:
linker_info
,
windows_subsystem
:
windows_subsystem
,
...
...
@@ -1410,7 +1273,8 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_i
}
}
fn
collect_and_partition_translation_items
<
'a
,
'tcx
>
(
scx
:
&
SharedCrateContext
<
'a
,
'tcx
>
)
fn
collect_and_partition_translation_items
<
'a
,
'tcx
>
(
scx
:
&
SharedCrateContext
<
'a
,
'tcx
>
,
exported_symbols
:
&
ExportedSymbols
)
->
(
FxHashSet
<
TransItem
<
'tcx
>>
,
Vec
<
CodegenUnit
<
'tcx
>>
)
{
let
time_passes
=
scx
.sess
()
.time_passes
();
...
...
@@ -1452,7 +1316,8 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
partitioning
::
partition
(
scx
,
items
.iter
()
.cloned
(),
strategy
,
&
inlining_map
)
&
inlining_map
,
exported_symbols
)
});
assert
!
(
scx
.tcx
()
.sess.opts.cg.codegen_units
==
codegen_units
.len
()
||
...
...
@@ -1480,7 +1345,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
let
mut
cgus
=
item_to_cgus
.get_mut
(
i
)
.unwrap_or
(
&
mut
empty
);
cgus
.as_mut_slice
()
.sort_by_key
(|
&
(
ref
name
,
_
)|
name
.clone
());
cgus
.dedup
();
for
&
(
ref
cgu_name
,
linkage
)
in
cgus
.iter
()
{
for
&
(
ref
cgu_name
,
(
linkage
,
_
)
)
in
cgus
.iter
()
{
output
.push_str
(
" "
);
output
.push_str
(
&
cgu_name
);
...
...
src/librustc_trans/callee.rs
浏览文件 @
2f07eb32
...
...
@@ -23,6 +23,7 @@
use
rustc
::
hir
::
def_id
::
DefId
;
use
rustc
::
ty
::
TypeFoldable
;
use
rustc
::
ty
::
subst
::
Substs
;
use
trans_item
::
TransItem
;
use
type_of
;
/// Translates a reference to a fn/method item, monomorphizing and
...
...
@@ -99,19 +100,32 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let
attrs
=
instance
.def
.attrs
(
ccx
.tcx
());
attributes
::
from_fn_attrs
(
ccx
,
&
attrs
,
llfn
);
let
instance_def_id
=
instance
.def_id
();
// Perhaps questionable, but we assume that anything defined
// *in Rust code* may unwind. Foreign items like `extern "C" {
// fn foo(); }` are assumed not to unwind **unless** they have
// a `#[unwind]` attribute.
if
!
tcx
.is_foreign_item
(
instance
.def_id
()
)
{
if
!
tcx
.is_foreign_item
(
instance
_def_id
)
{
attributes
::
unwind
(
llfn
,
true
);
}
unsafe
{
llvm
::
LLVMRustSetLinkage
(
llfn
,
llvm
::
Linkage
::
ExternalLinkage
);
if
ccx
.crate_trans_items
()
.contains
(
&
TransItem
::
Fn
(
instance
))
{
if
let
Some
(
node_id
)
=
tcx
.hir
.as_local_node_id
(
instance_def_id
)
{
if
!
ccx
.exported_symbols
()
.local_exports
()
.contains
(
&
node_id
)
{
llvm
::
LLVMRustSetVisibility
(
llfn
,
llvm
::
Visibility
::
Hidden
);
}
}
else
{
llvm
::
LLVMRustSetVisibility
(
llfn
,
llvm
::
Visibility
::
Hidden
);
}
}
}
if
ccx
.use_dll_storage_attrs
()
&&
ccx
.sess
()
.cstore
.is_dllimport_foreign_item
(
instance
.def_id
()
)
ccx
.sess
()
.cstore
.is_dllimport_foreign_item
(
instance
_def_id
)
{
unsafe
{
llvm
::
LLVMSetDLLStorageClass
(
llfn
,
llvm
::
DLLStorageClass
::
DllImport
);
...
...
src/librustc_trans/collector.rs
浏览文件 @
2f07eb32
...
...
@@ -243,21 +243,19 @@ fn new() -> InliningMap<'tcx> {
fn
record_accesses
<
I
>
(
&
mut
self
,
source
:
TransItem
<
'tcx
>
,
targets
:
I
)
where
I
:
Iterator
<
Item
=
(
TransItem
<
'tcx
>
,
bool
)
>
new_
targets
:
I
)
where
I
:
Iterator
<
Item
=
(
TransItem
<
'tcx
>
,
bool
)
>
+
ExactSizeIterator
{
assert
!
(
!
self
.index
.contains_key
(
&
source
));
let
start_index
=
self
.targets
.len
();
let
(
targets_size_hint
,
targets_size_hint_max
)
=
targets
.size_hint
();
debug_assert_eq!
(
targets_size_hint_max
,
Some
(
targets_size_hint
));
let
new_items_count
=
targets_size_hint
;
let
new_items_count
=
new_targets
.len
();
let
new_items_count_total
=
new_items_count
+
self
.targets
.len
();
self
.targets
.reserve
(
new_items_count
);
self
.inlines
.grow
(
new_items_count_total
);
for
(
i
,
(
target
,
inline
))
in
targets
.enumerate
()
{
for
(
i
,
(
target
,
inline
))
in
new_
targets
.enumerate
()
{
self
.targets
.push
(
target
);
if
inline
{
self
.inlines
.insert
(
i
+
start_index
);
...
...
src/librustc_trans/consts.rs
浏览文件 @
2f07eb32
...
...
@@ -104,6 +104,12 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
let
g
=
declare
::
define_global
(
ccx
,
&
sym
[
..
],
llty
)
.unwrap
();
if
!
ccx
.exported_symbols
()
.local_exports
()
.contains
(
&
id
)
{
unsafe
{
llvm
::
LLVMRustSetVisibility
(
g
,
llvm
::
Visibility
::
Hidden
);
}
}
(
g
,
attrs
)
}
...
...
@@ -243,8 +249,16 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let
name_str_ref
=
CStr
::
from_ptr
(
llvm
::
LLVMGetValueName
(
g
));
let
name_string
=
CString
::
new
(
name_str_ref
.to_bytes
())
.unwrap
();
llvm
::
LLVMSetValueName
(
g
,
empty_string
.as_ptr
());
let
linkage
=
llvm
::
LLVMRustGetLinkage
(
g
);
let
visibility
=
llvm
::
LLVMRustGetVisibility
(
g
);
let
new_g
=
llvm
::
LLVMRustGetOrInsertGlobal
(
ccx
.llmod
(),
name_string
.as_ptr
(),
val_llty
.to_ref
());
llvm
::
LLVMRustSetLinkage
(
new_g
,
linkage
);
llvm
::
LLVMRustSetVisibility
(
new_g
,
visibility
);
// To avoid breaking any invariants, we leave around the old
// global for the moment; we'll replace all references to it
// with the new global later. (See base::trans_crate.)
...
...
src/librustc_trans/context.rs
浏览文件 @
2f07eb32
...
...
@@ -16,11 +16,13 @@
use
rustc
::
traits
;
use
debuginfo
;
use
callee
;
use
back
::
symbol_export
::
ExportedSymbols
;
use
base
;
use
declare
;
use
monomorphize
::
Instance
;
use
partitioning
::
CodegenUnit
;
use
trans_item
::
TransItem
;
use
type_
::
Type
;
use
rustc_data_structures
::
base_n
;
use
rustc
::
session
::
config
::{
self
,
NoDebugInfo
,
OutputFilenames
};
...
...
@@ -28,13 +30,14 @@
use
rustc
::
ty
::
subst
::
Substs
;
use
rustc
::
ty
::{
self
,
Ty
,
TyCtxt
};
use
rustc
::
ty
::
layout
::{
LayoutCx
,
LayoutError
,
LayoutTyper
,
TyLayout
};
use
rustc
::
util
::
nodemap
::{
NodeSet
,
DefIdMap
,
FxHashMap
};
use
rustc
::
util
::
nodemap
::{
DefIdMap
,
FxHashMap
,
FxHashSet
};
use
std
::
ffi
::{
CStr
,
CString
};
use
std
::
cell
::{
Cell
,
RefCell
};
use
std
::
ptr
;
use
std
::
iter
;
use
std
::
str
;
use
std
::
sync
::
Arc
;
use
std
::
marker
::
PhantomData
;
use
syntax
::
ast
;
use
syntax
::
symbol
::
InternedString
;
...
...
@@ -76,7 +79,6 @@ pub fn extend(&mut self, stats: Stats) {
/// crate, so it must not contain references to any LLVM data structures
/// (aside from metadata-related ones).
pub
struct
SharedCrateContext
<
'a
,
'tcx
:
'a
>
{
exported_symbols
:
NodeSet
,
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
check_overflow
:
bool
,
...
...
@@ -94,6 +96,13 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> {
llcx
:
ContextRef
,
stats
:
Stats
,
codegen_unit
:
CodegenUnit
<
'tcx
>
,
/// The translation items of the whole crate.
crate_trans_items
:
Arc
<
FxHashSet
<
TransItem
<
'tcx
>>>
,
/// Information about which symbols are exported from the crate.
exported_symbols
:
Arc
<
ExportedSymbols
>
,
/// Cache instances of monomorphic and polymorphic items
instances
:
RefCell
<
FxHashMap
<
Instance
<
'tcx
>
,
ValueRef
>>
,
/// Cache generated vtables
...
...
@@ -265,7 +274,6 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont
impl
<
'b
,
'tcx
>
SharedCrateContext
<
'b
,
'tcx
>
{
pub
fn
new
(
tcx
:
TyCtxt
<
'b
,
'tcx
,
'tcx
>
,
exported_symbols
:
NodeSet
,
check_overflow
:
bool
,
output_filenames
:
&
'b
OutputFilenames
)
->
SharedCrateContext
<
'b
,
'tcx
>
{
...
...
@@ -315,7 +323,6 @@ pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
let
use_dll_storage_attrs
=
tcx
.sess.target.target.options.is_like_msvc
;
SharedCrateContext
{
exported_symbols
:
exported_symbols
,
tcx
:
tcx
,
check_overflow
:
check_overflow
,
use_dll_storage_attrs
:
use_dll_storage_attrs
,
...
...
@@ -335,10 +342,6 @@ pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
ty
.is_freeze
(
self
.tcx
,
ty
::
ParamEnv
::
empty
(
traits
::
Reveal
::
All
),
DUMMY_SP
)
}
pub
fn
exported_symbols
<
'a
>
(
&
'a
self
)
->
&
'a
NodeSet
{
&
self
.exported_symbols
}
pub
fn
tcx
<
'a
>
(
&
'a
self
)
->
TyCtxt
<
'a
,
'tcx
,
'tcx
>
{
self
.tcx
}
...
...
@@ -362,7 +365,9 @@ pub fn output_filenames(&self) -> &OutputFilenames {
impl
<
'a
,
'tcx
>
LocalCrateContext
<
'a
,
'tcx
>
{
pub
fn
new
(
shared
:
&
SharedCrateContext
<
'a
,
'tcx
>
,
codegen_unit
:
CodegenUnit
<
'tcx
>
)
codegen_unit
:
CodegenUnit
<
'tcx
>
,
crate_trans_items
:
Arc
<
FxHashSet
<
TransItem
<
'tcx
>>>
,
exported_symbols
:
Arc
<
ExportedSymbols
>
,)
->
LocalCrateContext
<
'a
,
'tcx
>
{
unsafe
{
// Append ".rs" to LLVM module identifier.
...
...
@@ -394,6 +399,8 @@ pub fn new(shared: &SharedCrateContext<'a, 'tcx>,
llcx
:
llcx
,
stats
:
Stats
::
default
(),
codegen_unit
:
codegen_unit
,
crate_trans_items
,
exported_symbols
,
instances
:
RefCell
::
new
(
FxHashMap
()),
vtables
:
RefCell
::
new
(
FxHashMap
()),
const_cstr_cache
:
RefCell
::
new
(
FxHashMap
()),
...
...
@@ -504,6 +511,14 @@ pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> {
&
self
.local
()
.codegen_unit
}
pub
fn
crate_trans_items
(
&
self
)
->
&
FxHashSet
<
TransItem
<
'tcx
>>
{
&
self
.local
()
.crate_trans_items
}
pub
fn
exported_symbols
(
&
self
)
->
&
ExportedSymbols
{
&
self
.local
()
.exported_symbols
}
pub
fn
td
(
&
self
)
->
llvm
::
TargetDataRef
{
unsafe
{
llvm
::
LLVMRustGetModuleDataLayout
(
self
.llmod
())
}
}
...
...
src/librustc_trans/debuginfo/utils.rs
浏览文件 @
2f07eb32
...
...
@@ -37,7 +37,7 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool
// visible). It might better to use the `exported_items` set from
// `driver::CrateAnalysis` in the future, but (atm) this set is not
// available in the translation pass.
!
cx
.
shared
()
.exported_symbol
s
()
.contains
(
&
node_id
)
!
cx
.
exported_symbols
()
.local_export
s
()
.contains
(
&
node_id
)
}
#[allow(non_snake_case)]
...
...
src/librustc_trans/partitioning.rs
浏览文件 @
2f07eb32
...
...
@@ -102,6 +102,7 @@
//! source-level module, functions from the same module will be available for
//! inlining, even when they are not marked #[inline].
use
back
::
symbol_export
::
ExportedSymbols
;
use
collector
::
InliningMap
;
use
common
;
use
context
::
SharedCrateContext
;
...
...
@@ -110,14 +111,15 @@
use
rustc
::
hir
::
def_id
::
DefId
;
use
rustc
::
hir
::
map
::
DefPathData
;
use
rustc
::
session
::
config
::
NUMBERED_CODEGEN_UNIT_MARKER
;
use
rustc
::
ty
::{
self
,
TyCtxt
};
use
rustc
::
ty
::{
self
,
TyCtxt
,
InstanceDef
};
use
rustc
::
ty
::
item_path
::
characteristic_def_id_of_type
;
use
rustc
::
util
::
nodemap
::{
FxHashMap
,
FxHashSet
};
use
rustc_incremental
::
IchHasher
;
use
std
::
collections
::
hash_map
::
Entry
;
use
std
::
hash
::
Hash
;
use
syntax
::
ast
::
NodeId
;
use
syntax
::
symbol
::{
Symbol
,
InternedString
};
use
trans_item
::{
TransItem
,
InstantiationMode
};
use
rustc
::
util
::
nodemap
::{
FxHashMap
,
FxHashSet
};
pub
enum
PartitioningStrategy
{
/// Generate one codegen unit per source-level module.
...
...
@@ -134,16 +136,16 @@ pub struct CodegenUnit<'tcx> {
/// as well as the crate name and disambiguator.
name
:
InternedString
,
items
:
FxHashMap
<
TransItem
<
'tcx
>
,
llvm
::
Linkage
>
,
items
:
FxHashMap
<
TransItem
<
'tcx
>
,
(
llvm
::
Linkage
,
llvm
::
Visibility
)
>
,
}
impl
<
'tcx
>
CodegenUnit
<
'tcx
>
{
pub
fn
new
(
name
:
InternedString
,
items
:
FxHashMap
<
TransItem
<
'tcx
>
,
llvm
::
Linkage
>
)
items
:
FxHashMap
<
TransItem
<
'tcx
>
,
(
llvm
::
Linkage
,
llvm
::
Visibility
)
>
)
->
Self
{
CodegenUnit
{
name
:
name
,
items
:
items
,
name
,
items
,
}
}
...
...
@@ -159,7 +161,7 @@ pub fn name(&self) -> &str {
&
self
.name
}
pub
fn
items
(
&
self
)
->
&
FxHashMap
<
TransItem
<
'tcx
>
,
llvm
::
Linkage
>
{
pub
fn
items
(
&
self
)
->
&
FxHashMap
<
TransItem
<
'tcx
>
,
(
llvm
::
Linkage
,
llvm
::
Visibility
)
>
{
&
self
.items
}
...
...
@@ -172,10 +174,11 @@ pub fn work_product_dep_node(&self) -> DepNode {
}
pub
fn
compute_symbol_name_hash
<
'a
>
(
&
self
,
scx
:
&
SharedCrateContext
<
'a
,
'tcx
>
)
scx
:
&
SharedCrateContext
<
'a
,
'tcx
>
,
exported_symbols
:
&
ExportedSymbols
)
->
u64
{
let
mut
state
=
IchHasher
::
new
();
let
exported_symbols
=
scx
.exported_symbol
s
();
let
exported_symbols
=
exported_symbols
.local_export
s
();
let
all_items
=
self
.items_in_deterministic_order
(
scx
.tcx
());
for
(
item
,
_
)
in
all_items
{
let
symbol_name
=
item
.symbol_name
(
scx
.tcx
());
...
...
@@ -200,7 +203,8 @@ pub fn compute_symbol_name_hash<'a>(&self,
pub
fn
items_in_deterministic_order
<
'a
>
(
&
self
,
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
)
->
Vec
<
(
TransItem
<
'tcx
>
,
llvm
::
Linkage
)
>
{
->
Vec
<
(
TransItem
<
'tcx
>
,
(
llvm
::
Linkage
,
llvm
::
Visibility
))
>
{
// The codegen tests rely on items being process in the same order as
// they appear in the file, so for local items, we sort by node_id first
#[derive(PartialEq,
Eq,
PartialOrd,
Ord)]
...
...
@@ -233,7 +237,8 @@ fn item_sort_key<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub
fn
partition
<
'a
,
'tcx
,
I
>
(
scx
:
&
SharedCrateContext
<
'a
,
'tcx
>
,
trans_items
:
I
,
strategy
:
PartitioningStrategy
,
inlining_map
:
&
InliningMap
<
'tcx
>
)
inlining_map
:
&
InliningMap
<
'tcx
>
,
exported_symbols
:
&
ExportedSymbols
)
->
Vec
<
CodegenUnit
<
'tcx
>>
where
I
:
Iterator
<
Item
=
TransItem
<
'tcx
>>
{
...
...
@@ -243,6 +248,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
// respective 'home' codegen unit. Regular translation items are all
// functions and statics defined in the local crate.
let
mut
initial_partitioning
=
place_root_translation_items
(
scx
,
exported_symbols
,
trans_items
);
debug_dump
(
tcx
,
"INITIAL PARTITONING:"
,
initial_partitioning
.codegen_units
.iter
());
...
...
@@ -259,13 +265,22 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
// translation items have to go into each codegen unit. These additional
// translation items can be drop-glue, functions from external crates, and
// local functions the definition of which is marked with #[inline].
let
post_inlining
=
place_inlined_translation_items
(
initial_partitioning
,
let
mut
post_inlining
=
place_inlined_translation_items
(
initial_partitioning
,
inlining_map
);
debug_dump
(
tcx
,
"POST INLINING:"
,
post_inlining
.0
.iter
());
debug_dump
(
tcx
,
"POST INLINING:"
,
post_inlining
.codegen_units
.iter
());
// Next we try to make as many symbols "internal" as possible, so LLVM has
// more freedom to optimize.
internalize_symbols
(
tcx
,
&
mut
post_inlining
,
inlining_map
);
// Finally, sort by codegen unit name, so that we get deterministic results
let
mut
result
=
post_inlining
.0
;
let
PostInliningPartitioning
{
codegen_units
:
mut
result
,
trans_item_placements
:
_
,
internalization_candidates
:
_
,
}
=
post_inlining
;
result
.sort_by
(|
cgu1
,
cgu2
|
{
(
&
cgu1
.name
[
..
])
.cmp
(
&
cgu2
.name
[
..
])
});
...
...
@@ -284,19 +299,37 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
struct
PreInliningPartitioning
<
'tcx
>
{
codegen_units
:
Vec
<
CodegenUnit
<
'tcx
>>
,
roots
:
FxHashSet
<
TransItem
<
'tcx
>>
,
internalization_candidates
:
FxHashSet
<
TransItem
<
'tcx
>>
,
}
struct
PostInliningPartitioning
<
'tcx
>
(
Vec
<
CodegenUnit
<
'tcx
>>
);
/// For symbol internalization, we need to know whether a symbol/trans-item is
/// accessed from outside the codegen unit it is defined in. This type is used
/// to keep track of that.
#[derive(Clone,
PartialEq,
Eq,
Debug)]
enum
TransItemPlacement
{
SingleCgu
{
cgu_name
:
InternedString
},
MultipleCgus
,
}
struct
PostInliningPartitioning
<
'tcx
>
{
codegen_units
:
Vec
<
CodegenUnit
<
'tcx
>>
,
trans_item_placements
:
FxHashMap
<
TransItem
<
'tcx
>
,
TransItemPlacement
>
,
internalization_candidates
:
FxHashSet
<
TransItem
<
'tcx
>>
,
}
fn
place_root_translation_items
<
'a
,
'tcx
,
I
>
(
scx
:
&
SharedCrateContext
<
'a
,
'tcx
>
,
exported_symbols
:
&
ExportedSymbols
,
trans_items
:
I
)
->
PreInliningPartitioning
<
'tcx
>
where
I
:
Iterator
<
Item
=
TransItem
<
'tcx
>>
{
let
tcx
=
scx
.tcx
();
let
exported_symbols
=
exported_symbols
.local_exports
();
let
mut
roots
=
FxHashSet
();
let
mut
codegen_units
=
FxHashMap
();
let
is_incremental_build
=
tcx
.sess.opts.incremental
.is_some
();
let
mut
internalization_candidates
=
FxHashSet
();
for
trans_item
in
trans_items
{
let
is_root
=
trans_item
.instantiation_mode
(
tcx
)
==
InstantiationMode
::
GloballyShared
;
...
...
@@ -318,18 +351,52 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
let
mut
codegen_unit
=
codegen_units
.entry
(
codegen_unit_name
.clone
())
.or_insert_with
(
make_codegen_unit
);
let
linkage
=
match
trans_item
.explicit_linkage
(
tcx
)
{
Some
(
explicit_linkage
)
=>
explicit_linkage
,
let
(
linkage
,
visibility
)
=
match
trans_item
.explicit_linkage
(
tcx
)
{
Some
(
explicit_linkage
)
=>
(
explicit_linkage
,
llvm
::
Visibility
::
Default
)
,
None
=>
{
match
trans_item
{
TransItem
::
Fn
(
..
)
|
TransItem
::
Static
(
..
)
|
TransItem
::
GlobalAsm
(
..
)
=>
llvm
::
ExternalLinkage
,
TransItem
::
Fn
(
ref
instance
)
=>
{
let
visibility
=
match
instance
.def
{
InstanceDef
::
Item
(
def_id
)
=>
{
if
let
Some
(
node_id
)
=
tcx
.hir
.as_local_node_id
(
def_id
)
{
if
exported_symbols
.contains
(
&
node_id
)
{
llvm
::
Visibility
::
Default
}
else
{
internalization_candidates
.insert
(
trans_item
);
llvm
::
Visibility
::
Hidden
}
}
else
{
internalization_candidates
.insert
(
trans_item
);
llvm
::
Visibility
::
Hidden
}
}
InstanceDef
::
FnPtrShim
(
..
)
|
InstanceDef
::
Virtual
(
..
)
|
InstanceDef
::
Intrinsic
(
..
)
|
InstanceDef
::
ClosureOnceShim
{
..
}
|
InstanceDef
::
DropGlue
(
..
)
=>
{
bug!
(
"partitioning: Encountered unexpected
root translation item: {:?}"
,
trans_item
)
}
};
(
llvm
::
ExternalLinkage
,
visibility
)
}
TransItem
::
Static
(
node_id
)
|
TransItem
::
GlobalAsm
(
node_id
)
=>
{
let
visibility
=
if
exported_symbols
.contains
(
&
node_id
)
{
llvm
::
Visibility
::
Default
}
else
{
internalization_candidates
.insert
(
trans_item
);
llvm
::
Visibility
::
Hidden
};
(
llvm
::
ExternalLinkage
,
visibility
)
}
}
}
};
codegen_unit
.items
.insert
(
trans_item
,
linkage
);
codegen_unit
.items
.insert
(
trans_item
,
(
linkage
,
visibility
)
);
roots
.insert
(
trans_item
);
}
}
...
...
@@ -338,15 +405,16 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
// crate with just types (for example), we could wind up with no CGU
if
codegen_units
.is_empty
()
{
let
codegen_unit_name
=
Symbol
::
intern
(
FALLBACK_CODEGEN_UNIT
)
.as_str
();
codegen_units
.
entry
(
codegen_unit_name
.clone
())
.or_insert_with
(||
CodegenUnit
::
empty
(
codegen_unit_name
.clone
()));
codegen_units
.
insert
(
codegen_unit_name
.clone
(),
CodegenUnit
::
empty
(
codegen_unit_name
.clone
()));
}
PreInliningPartitioning
{
codegen_units
:
codegen_units
.into_iter
()
.map
(|(
_
,
codegen_unit
)|
codegen_unit
)
.collect
(),
roots
:
roots
,
roots
,
internalization_candidates
,
}
}
...
...
@@ -388,37 +456,75 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit
inlining_map
:
&
InliningMap
<
'tcx
>
)
->
PostInliningPartitioning
<
'tcx
>
{
let
mut
new_partitioning
=
Vec
::
new
();
let
mut
trans_item_placements
=
FxHashMap
();
let
PreInliningPartitioning
{
codegen_units
:
initial_cgus
,
roots
,
internalization_candidates
,
}
=
initial_partitioning
;
let
single_codegen_unit
=
initial_cgus
.len
()
==
1
;
for
codegen_unit
in
&
initial_partitioning
.codegen_units
[
..
]
{
for
old_codegen_unit
in
initial_cgus
{
// Collect all items that need to be available in this codegen unit
let
mut
reachable
=
FxHashSet
();
for
root
in
codegen_unit
.items
.keys
()
{
for
root
in
old_
codegen_unit
.items
.keys
()
{
follow_inlining
(
*
root
,
inlining_map
,
&
mut
reachable
);
}
let
mut
new_codegen_unit
=
CodegenUnit
::
empty
(
codegen_unit
.name
.clone
());
let
mut
new_codegen_unit
=
CodegenUnit
{
name
:
old_codegen_unit
.name
,
items
:
FxHashMap
(),
};
// Add all translation items that are not already there
for
trans_item
in
reachable
{
if
let
Some
(
linkage
)
=
codegen_unit
.items
.get
(
&
trans_item
)
{
if
let
Some
(
linkage
)
=
old_
codegen_unit
.items
.get
(
&
trans_item
)
{
// This is a root, just copy it over
new_codegen_unit
.items
.insert
(
trans_item
,
*
linkage
);
}
else
{
if
initial_partitioning
.
roots
.contains
(
&
trans_item
)
{
if
roots
.contains
(
&
trans_item
)
{
bug!
(
"GloballyShared trans-item inlined into other CGU:
\
{:?}"
,
trans_item
);
}
// This is a cgu-private copy
new_codegen_unit
.items
.insert
(
trans_item
,
llvm
::
InternalLinkage
);
new_codegen_unit
.items
.insert
(
trans_item
,
(
llvm
::
InternalLinkage
,
llvm
::
Visibility
::
Default
));
}
if
!
single_codegen_unit
{
// If there is more than one codegen unit, we need to keep track
// in which codegen units each translation item is placed:
match
trans_item_placements
.entry
(
trans_item
)
{
Entry
::
Occupied
(
e
)
=>
{
let
placement
=
e
.into_mut
();
debug_assert!
(
match
*
placement
{
TransItemPlacement
::
SingleCgu
{
ref
cgu_name
}
=>
{
*
cgu_name
!=
new_codegen_unit
.name
}
TransItemPlacement
::
MultipleCgus
=>
true
,
});
*
placement
=
TransItemPlacement
::
MultipleCgus
;
}
Entry
::
Vacant
(
e
)
=>
{
e
.insert
(
TransItemPlacement
::
SingleCgu
{
cgu_name
:
new_codegen_unit
.name
.clone
()
});
}
}
}
}
new_partitioning
.push
(
new_codegen_unit
);
}
return
PostInliningPartitioning
(
new_partitioning
);
return
PostInliningPartitioning
{
codegen_units
:
new_partitioning
,
trans_item_placements
,
internalization_candidates
,
};
fn
follow_inlining
<
'tcx
>
(
trans_item
:
TransItem
<
'tcx
>
,
inlining_map
:
&
InliningMap
<
'tcx
>
,
...
...
@@ -433,6 +539,72 @@ fn follow_inlining<'tcx>(trans_item: TransItem<'tcx>,
}
}
fn
internalize_symbols
<
'a
,
'tcx
>
(
_
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
partitioning
:
&
mut
PostInliningPartitioning
<
'tcx
>
,
inlining_map
:
&
InliningMap
<
'tcx
>
)
{
if
partitioning
.codegen_units
.len
()
==
1
{
// Fast path for when there is only one codegen unit. In this case we
// can internalize all candidates, since there is nowhere else they
// could be accessed from.
for
cgu
in
&
mut
partitioning
.codegen_units
{
for
candidate
in
&
partitioning
.internalization_candidates
{
cgu
.items
.insert
(
*
candidate
,
(
llvm
::
InternalLinkage
,
llvm
::
Visibility
::
Default
));
}
}
return
;
}
// Build a map from every translation item to all the translation items that
// reference it.
let
mut
accessor_map
:
FxHashMap
<
TransItem
<
'tcx
>
,
Vec
<
TransItem
<
'tcx
>>>
=
FxHashMap
();
inlining_map
.iter_accesses
(|
accessor
,
accessees
|
{
for
accessee
in
accessees
{
accessor_map
.entry
(
*
accessee
)
.or_insert
(
Vec
::
new
())
.push
(
accessor
);
}
});
let
trans_item_placements
=
&
partitioning
.trans_item_placements
;
// For each internalization candidates in each codegen unit, check if it is
// accessed from outside its defining codegen unit.
for
cgu
in
&
mut
partitioning
.codegen_units
{
let
home_cgu
=
TransItemPlacement
::
SingleCgu
{
cgu_name
:
cgu
.name
.clone
()
};
'item
:
for
(
accessee
,
&
mut
(
ref
mut
linkage
,
_
))
in
&
mut
cgu
.items
{
if
!
partitioning
.internalization_candidates
.contains
(
accessee
)
{
// This item is no candidate for internalizing, so skip it.
continue
}
debug_assert_eq!
(
trans_item_placements
[
accessee
],
home_cgu
);
if
let
Some
(
accessors
)
=
accessor_map
.get
(
accessee
)
{
if
accessors
.iter
()
.filter_map
(|
accessor
|
{
// Some accessors might not have been
// instantiated. We can safely ignore those.
trans_item_placements
.get
(
accessor
)
})
.any
(|
placement
|
*
placement
!=
home_cgu
)
{
// Found an accessor from another CGU, so skip to the next
// item without marking this one as internal.
continue
'item
;
}
}
// If we got here, we did not find any accesses from other CGUs,
// so it's fine to make this translation item internal.
*
linkage
=
llvm
::
InternalLinkage
;
}
}
}
fn
characteristic_def_id_of_trans_item
<
'a
,
'tcx
>
(
scx
:
&
SharedCrateContext
<
'a
,
'tcx
>
,
trans_item
:
TransItem
<
'tcx
>
)
->
Option
<
DefId
>
{
...
...
src/librustc_trans/trans_item.rs
浏览文件 @
2f07eb32
...
...
@@ -99,7 +99,8 @@ pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
pub
fn
predefine
(
&
self
,
ccx
:
&
CrateContext
<
'a
,
'tcx
>
,
linkage
:
llvm
::
Linkage
)
{
linkage
:
llvm
::
Linkage
,
visibility
:
llvm
::
Visibility
)
{
debug!
(
"BEGIN PREDEFINING '{} ({})' in cgu {}"
,
self
.to_string
(
ccx
.tcx
()),
self
.to_raw_string
(),
...
...
@@ -111,10 +112,10 @@ pub fn predefine(&self,
match
*
self
{
TransItem
::
Static
(
node_id
)
=>
{
TransItem
::
predefine_static
(
ccx
,
node_id
,
linkage
,
&
symbol_name
);
TransItem
::
predefine_static
(
ccx
,
node_id
,
linkage
,
visibility
,
&
symbol_name
);
}
TransItem
::
Fn
(
instance
)
=>
{
TransItem
::
predefine_fn
(
ccx
,
instance
,
linkage
,
&
symbol_name
);
TransItem
::
predefine_fn
(
ccx
,
instance
,
linkage
,
visibility
,
&
symbol_name
);
}
TransItem
::
GlobalAsm
(
..
)
=>
{}
}
...
...
@@ -128,6 +129,7 @@ pub fn predefine(&self,
fn
predefine_static
(
ccx
:
&
CrateContext
<
'a
,
'tcx
>
,
node_id
:
ast
::
NodeId
,
linkage
:
llvm
::
Linkage
,
visibility
:
llvm
::
Visibility
,
symbol_name
:
&
str
)
{
let
def_id
=
ccx
.tcx
()
.hir
.local_def_id
(
node_id
);
let
instance
=
Instance
::
mono
(
ccx
.tcx
(),
def_id
);
...
...
@@ -139,7 +141,10 @@ fn predefine_static(ccx: &CrateContext<'a, 'tcx>,
&
format!
(
"symbol `{}` is already defined"
,
symbol_name
))
});
unsafe
{
llvm
::
LLVMRustSetLinkage
(
g
,
linkage
)
};
unsafe
{
llvm
::
LLVMRustSetLinkage
(
g
,
linkage
);
llvm
::
LLVMRustSetVisibility
(
g
,
visibility
);
}
ccx
.instances
()
.borrow_mut
()
.insert
(
instance
,
g
);
ccx
.statics
()
.borrow_mut
()
.insert
(
g
,
def_id
);
...
...
@@ -148,6 +153,7 @@ fn predefine_static(ccx: &CrateContext<'a, 'tcx>,
fn
predefine_fn
(
ccx
:
&
CrateContext
<
'a
,
'tcx
>
,
instance
:
Instance
<
'tcx
>
,
linkage
:
llvm
::
Linkage
,
visibility
:
llvm
::
Visibility
,
symbol_name
:
&
str
)
{
assert
!
(
!
instance
.substs
.needs_infer
()
&&
!
instance
.substs
.has_param_types
());
...
...
@@ -172,6 +178,10 @@ fn predefine_fn(ccx: &CrateContext<'a, 'tcx>,
unsafe
{
llvm
::
LLVMRustSetVisibility
(
lldecl
,
llvm
::
Visibility
::
Hidden
);
}
}
else
{
unsafe
{
llvm
::
LLVMRustSetVisibility
(
lldecl
,
visibility
);
}
}
debug!
(
"predefine_fn: mono_ty = {:?} instance = {:?}"
,
mono_ty
,
instance
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录