Skip to content

Commit a0a2544

Browse files
committed
rustc_metadata encoder/decoder + refactor
1 parent 9e5c56e commit a0a2544

File tree

20 files changed

+485
-288
lines changed

20 files changed

+485
-288
lines changed

src/librustc/cg.rs

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//! Call graph metadata
2+
3+
use crate::hir::def_id::{DefId, LOCAL_CRATE};
4+
use crate::ty::subst::SubstsRef;
5+
use crate::ty::{
6+
ExistentialTraitRef, Instance, InstanceDef, ParamEnv, PolyTraitRef, TraitRef, Ty, TyCtxt,
7+
};
8+
use crate::mir::interpret::{AllocKind, Allocation};
9+
10+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
11+
use rustc_macros::HashStable;
12+
13+
use std::sync::Arc;
14+
15+
/// Call graph metadata loaded from an external crate
16+
#[derive(HashStable)]
17+
pub struct ExternCallGraphMetadata<'tcx> {
18+
/// list of functions casted / coerced into function pointers
19+
pub function_pointers: Vec<(DefId, SubstsRef<'tcx>)>,
20+
21+
/// list of types casted / coerced into trait objects
22+
pub trait_objects: Vec<TraitRef<'tcx>>,
23+
24+
/// list of types whose drop glue may be invoked by trait object drop glue
25+
pub dynamic_drop_glue: Vec<(Ty<'tcx>, Vec<ExistentialTraitRef<'tcx>>)>,
26+
}
27+
28+
impl<'tcx> ExternCallGraphMetadata<'tcx> {
29+
pub fn empty() -> Self {
30+
ExternCallGraphMetadata {
31+
function_pointers: vec![],
32+
trait_objects: vec![],
33+
dynamic_drop_glue: vec![],
34+
}
35+
}
36+
}
37+
38+
/// Local call graph metadata
39+
#[derive(Clone, Default, HashStable)]
40+
pub struct LocalCallGraphMetadata<'tcx> {
41+
/// list of functions casted / coerced into function pointers
42+
pub function_pointers: FxHashSet<(DefId, SubstsRef<'tcx>)>,
43+
44+
/// list of types casted / coerced into trait objects
45+
pub trait_objects: FxHashSet<TraitRef<'tcx>>,
46+
47+
/// list of types whose drop glue may be invoked by trait object drop glue
48+
pub dynamic_drop_glue: FxHashMap<Ty<'tcx>, FxHashSet<ExistentialTraitRef<'tcx>>>,
49+
}
50+
51+
impl<'tcx> LocalCallGraphMetadata<'tcx> {
52+
/// Registers `alloc` as a const-evaluated trait object
53+
///
54+
/// Returns `false` if `alloc` was *not* a trait object
55+
pub fn register_const_trait_object(&mut self,
56+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
57+
alloc: &'tcx Allocation) -> bool {
58+
let has_drop_glue = alloc.relocations.values().any(|(_, inner)| {
59+
let kind = tcx.alloc_map.lock().get(*inner);
60+
61+
if let Some(AllocKind::Function(instance)) = kind {
62+
if let InstanceDef::DropGlue(..) = instance.def {
63+
return true;
64+
}
65+
}
66+
67+
false
68+
});
69+
70+
if has_drop_glue {
71+
for (_, inner) in alloc.relocations.values() {
72+
let kind = tcx.alloc_map.lock().get(*inner);
73+
74+
if let Some(AllocKind::Function(method)) = kind {
75+
self.register_dynamic_dispatch(tcx, method);
76+
} else {
77+
bug!("unexpected `AllocKind`: {:?}", kind);
78+
}
79+
}
80+
}
81+
82+
has_drop_glue
83+
}
84+
85+
/// Registers that `method` is dynamically dispatched
86+
pub fn register_dynamic_dispatch(&mut self,
87+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
88+
method: Instance<'tcx>) {
89+
if let Some((trait_ref, _)) = method.trait_ref_and_method(tcx) {
90+
self.trait_objects.insert(trait_ref);
91+
}
92+
}
93+
94+
/// Registers that `function` is casted / coerced into a function pointer
95+
pub fn register_function_pointer(&mut self, function: Instance<'tcx>) {
96+
self.function_pointers.insert((function.def_id(), function.substs));
97+
}
98+
99+
/// Registers that `poly_trait_ref` is used as a trait object
100+
pub fn register_trait_object(&mut self,
101+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
102+
poly_trait_ref: PolyTraitRef<'tcx>) {
103+
let trait_ref = tcx.normalize_erasing_late_bound_regions(
104+
ParamEnv::reveal_all(),
105+
&poly_trait_ref,
106+
);
107+
108+
self.trait_objects.insert(trait_ref);
109+
110+
let self_ty = trait_ref.self_ty();
111+
let existential_trait_ref = ExistentialTraitRef::erase_self_ty(tcx, trait_ref);
112+
113+
self.dynamic_drop_glue.entry(self_ty).or_default().insert(existential_trait_ref);
114+
}
115+
116+
pub fn extend(&mut self, other: Self) {
117+
self.function_pointers.extend(other.function_pointers);
118+
self.trait_objects.extend(other.trait_objects);
119+
120+
for (ty, traits) in other.dynamic_drop_glue {
121+
self.dynamic_drop_glue.entry(ty).or_default().extend(traits);
122+
}
123+
}
124+
}
125+
126+
/// Local and external call graph metadata
127+
#[derive(HashStable)]
128+
pub struct AllCallGraphMetadata<'tcx> {
129+
/// list of functions casted / coerced into function pointers
130+
pub function_pointers: FxHashSet<(DefId, SubstsRef<'tcx>)>,
131+
132+
/// list of types casted / coerced into trait objects
133+
pub trait_objects: FxHashSet<TraitRef<'tcx>>,
134+
135+
/// list of types whose drop glue may be invoked by trait object drop glue
136+
pub dynamic_drop_glue: FxHashMap<Ty<'tcx>, Arc<FxHashSet<ExistentialTraitRef<'tcx>>>>,
137+
}
138+
139+
pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> AllCallGraphMetadata<'tcx> {
140+
let mut cg = (*tcx.local_call_graph_metadata(LOCAL_CRATE)).clone();
141+
142+
for &cnum in tcx.crates().iter() {
143+
let ext = tcx.extern_call_graph_metadata(cnum);
144+
145+
cg.function_pointers.extend(ext.function_pointers.iter().cloned());
146+
cg.trait_objects.extend(ext.trait_objects.iter().cloned());
147+
148+
for (ty, traits) in &ext.dynamic_drop_glue {
149+
cg.dynamic_drop_glue.entry(*ty).or_default().extend(traits.iter().cloned());
150+
}
151+
}
152+
153+
AllCallGraphMetadata {
154+
function_pointers: cg.function_pointers,
155+
trait_objects: cg.trait_objects,
156+
dynamic_drop_glue: cg.dynamic_drop_glue.into_iter().map(|(ty, traits)| {
157+
(ty, Arc::new(traits))
158+
}).collect(),
159+
}
160+
}

src/librustc/ich/impls_ty.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
//! from rustc::ty in no particular order.
33
44
use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
5+
use crate::hir::def_id::DefId;
6+
use crate::ty::Ty;
7+
use crate::ty::subst::SubstsRef;
58
use rustc_data_structures::fx::FxHashMap;
69
use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
710
StableHasher, StableHasherResult};
@@ -54,7 +57,7 @@ impl<'a, 'gcx, T> ToStableHashKey<StableHashingContext<'a>> for &'gcx ty::List<T
5457
}
5558
}
5659

57-
impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for ty::Instance<'tcx> {
60+
impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for ty::ExistentialTraitRef<'tcx> {
5861
type KeyType = Fingerprint;
5962

6063
#[inline]
@@ -66,7 +69,31 @@ impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for ty::Instance<'tcx>
6669
}
6770
}
6871

69-
impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for ty::ExistentialTraitRef<'tcx> {
72+
impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for ty::TraitRef<'tcx> {
73+
type KeyType = Fingerprint;
74+
75+
#[inline]
76+
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint {
77+
let mut hasher = StableHasher::new();
78+
let mut hcx: StableHashingContext<'a> = hcx.clone();
79+
self.hash_stable(&mut hcx, &mut hasher);
80+
hasher.finish()
81+
}
82+
}
83+
84+
impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for (DefId, SubstsRef<'tcx>) {
85+
type KeyType = Fingerprint;
86+
87+
#[inline]
88+
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint {
89+
let mut hasher = StableHasher::new();
90+
let mut hcx: StableHashingContext<'a> = hcx.clone();
91+
self.hash_stable(&mut hcx, &mut hasher);
92+
hasher.finish()
93+
}
94+
}
95+
96+
impl<'a, 'tcx> ToStableHashKey<StableHashingContext<'a>> for Ty<'tcx> {
7097
type KeyType = Fingerprint;
7198

7299
#[inline]

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ pub mod diagnostics;
103103
#[macro_use]
104104
pub mod query;
105105

106+
pub mod cg;
106107
pub mod cfg;
107108
pub mod dep_graph;
108109
pub mod hir;

src/librustc/query/mod.rs

+27-11
Original file line numberDiff line numberDiff line change
@@ -864,9 +864,7 @@ rustc_queries! {
864864
query collect_and_partition_mono_items(_: CrateNum) -> (
865865
Arc<DefIdSet>,
866866
Arc<Vec<Arc<CodegenUnit<'tcx>>>>,
867-
Arc<FxHashSet<ty::Instance<'tcx>>>,
868-
Arc<FxHashSet<ty::Instance<'tcx>>>,
869-
Arc<FxHashMap<ty::Instance<'tcx>, Arc<FxHashSet<ty::ExistentialTraitRef<'tcx>>>>>
867+
Arc<cg::LocalCallGraphMetadata<'tcx>>,
870868
) {
871869
eval_always
872870
desc { "collect_and_partition_mono_items" }
@@ -881,23 +879,41 @@ rustc_queries! {
881879
}
882880

883881
// -Z call-metadata
884-
// functions that may be called via a function pointer
885-
query function_pointer(instance: ty::Instance<'tcx>) -> bool {
882+
query extern_call_graph_metadata(_: CrateNum) -> Lrc<cg::ExternCallGraphMetadata<'tcx>> {
886883
no_force
887-
desc { "checking if `{}` may be called via a function pointer", instance }
884+
desc { "loading external call graph metadata" }
888885
}
889886

890-
// trait methods that may be called via dynamic dispatch
891-
query dynamic_dispatch(instance: ty::Instance<'tcx>) -> bool {
887+
query local_call_graph_metadata(_: CrateNum) -> Arc<cg::LocalCallGraphMetadata<'tcx>> {
892888
no_force
893-
desc { "checking if `{}` may be called via dynamic dispatch", instance }
889+
desc { "local call graph metadata" }
894890
}
895891

896-
query drop_glue(instance: ty::Instance<'tcx>) ->
892+
query all_call_graph_metadata(_: CrateNum) -> Lrc<cg::AllCallGraphMetadata<'tcx>> {
893+
no_force
894+
desc { "all call graph metadata" }
895+
}
896+
897+
// has this function being casted / coerced into a function pointer?
898+
query is_function_pointer(key: (DefId, SubstsRef<'tcx>)) -> bool {
899+
no_force
900+
desc {
901+
"checking if `{:?}` ({:?}) has been casted into a function pointer", key.0, key.1
902+
}
903+
}
904+
905+
// has this type being casted / coerced into a trait object?
906+
query is_trait_object(trait_ref: ty::TraitRef<'tcx>) -> bool {
907+
no_force
908+
desc { "checking if `{}` has been casted / coerced into a trait object", trait_ref }
909+
}
910+
911+
// returns the list of traits whose trait objects may call into this type drop glue (if any)
912+
query dynamic_drop_glue(ty: Ty<'tcx>) ->
897913
Option<Arc<FxHashSet<ty::ExistentialTraitRef<'tcx>>>>
898914
{
899915
no_force
900-
desc { "checking if `{}` may be called by a trait object destructor", instance }
916+
desc { "checking if `{}` drop glue is called by trait objects drop glue", ty }
901917
}
902918
}
903919

src/librustc/ty/context.rs

+18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Type context book-keeping.
22
3+
use crate::cg;
34
use crate::dep_graph::DepGraph;
45
use crate::dep_graph::{self, DepNode, DepConstructor};
56
use crate::session::Session;
@@ -3099,4 +3100,21 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
30993100
assert_eq!(cnum, LOCAL_CRATE);
31003101
attr::contains_name(tcx.hir().krate_attrs(), "compiler_builtins")
31013102
};
3103+
3104+
providers.all_call_graph_metadata = |tcx, cnum| {
3105+
assert_eq!(cnum, LOCAL_CRATE);
3106+
Lrc::new(cg::collect(tcx))
3107+
};
3108+
providers.is_function_pointer = |tcx, key| {
3109+
let cg = tcx.all_call_graph_metadata(LOCAL_CRATE);
3110+
cg.function_pointers.contains(&key)
3111+
};
3112+
providers.is_trait_object = |tcx, trait_ref| {
3113+
let cg = tcx.all_call_graph_metadata(LOCAL_CRATE);
3114+
cg.trait_objects.contains(&trait_ref)
3115+
};
3116+
providers.dynamic_drop_glue = |tcx, ty| {
3117+
let cg = tcx.all_call_graph_metadata(LOCAL_CRATE);
3118+
cg.dynamic_drop_glue.get(&ty).cloned()
3119+
};
31023120
}

src/librustc/ty/instance.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ impl<'a, 'tcx> Instance<'tcx> {
5555
)
5656
}
5757

58+
/// If this `Instance` corresponds to a trait method this returns the `TraitRef` and the method
59+
/// name
5860
pub fn trait_ref_and_method(
5961
&self,
6062
tcx: TyCtxt<'a, 'tcx, 'tcx>,
61-
) -> Option<(ty::ExistentialTraitRef<'tcx>, Symbol)> {
63+
) -> Option<(ty::TraitRef<'tcx>, Symbol)> {
6264
let def_id = self.def_id();
6365
if let Some(Def::Method(..)) = tcx.describe_def(def_id) {
6466
let item = tcx.associated_item(def_id);
@@ -69,17 +71,12 @@ impl<'a, 'tcx> Instance<'tcx> {
6971
}
7072

7173
AssociatedItemContainer::ImplContainer(impl_def_id) => {
72-
if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
73-
trait_ref
74-
} else {
75-
// inherent method
76-
return None;
77-
}
74+
tcx.impl_trait_ref(impl_def_id)?
7875
}
7976
};
8077

8178
Some((
82-
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
79+
trait_ref,
8380
item.ident.name,
8481
))
8582
} else {

src/librustc/ty/query/keys.rs

+10
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ impl<'tcx> Key for ty::Instance<'tcx> {
4545
}
4646
}
4747

48+
impl<'tcx> Key for ty::TraitRef<'tcx> {
49+
fn query_crate(&self) -> CrateNum {
50+
LOCAL_CRATE
51+
}
52+
53+
fn default_span(&self, tcx: TyCtxt<'_, '_, '_>) -> Span {
54+
tcx.def_span(self.def_id)
55+
}
56+
}
57+
4858
impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
4959
fn query_crate(&self) -> CrateNum {
5060
self.instance.query_crate()

src/librustc/ty/query/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::cg;
12
use crate::dep_graph::{self, DepNode};
23
use crate::hir::def_id::{CrateNum, DefId, DefIndex};
34
use crate::hir::def::{Def, Export};

0 commit comments

Comments
 (0)