Skip to content

Commit 3037965

Browse files
committedOct 14, 2017
Auto merge of #45137 - theotherjimmy:vtable-methods-query, r=nikomatsakis
Queryify Vtable methods This query might come with a downside: It converts an iterator to a Vec, which may increase the working set of rustc on programs that use many many traits (I think that's where this is used).
2 parents 2aeff0f + fcb8bc9 commit 3037965

File tree

8 files changed

+79
-147
lines changed

8 files changed

+79
-147
lines changed
 

‎src/librustc/dep_graph/dep_node.rs

+1
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ define_dep_nodes!( <'tcx>
506506
[] SpecializationGraph(DefId),
507507
[] ObjectSafety(DefId),
508508
[] FulfillObligation { param_env: ParamEnv<'tcx>, trait_ref: PolyTraitRef<'tcx> },
509+
[] VtableMethods { trait_ref: PolyTraitRef<'tcx> },
509510

510511
[] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
511512
[] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },

‎src/librustc/traits/mod.rs

+48-44
Original file line numberDiff line numberDiff line change
@@ -650,53 +650,55 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
650650
/// Given a trait `trait_ref`, iterates the vtable entries
651651
/// that come from `trait_ref`, including its supertraits.
652652
#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
653-
pub fn get_vtable_methods<'a, 'tcx>(
653+
fn vtable_methods<'a, 'tcx>(
654654
tcx: TyCtxt<'a, 'tcx, 'tcx>,
655655
trait_ref: ty::PolyTraitRef<'tcx>)
656-
-> impl Iterator<Item=Option<(DefId, &'tcx Substs<'tcx>)>> + 'a
656+
-> Rc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>
657657
{
658-
debug!("get_vtable_methods({:?})", trait_ref);
659-
660-
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
661-
let trait_methods = tcx.associated_items(trait_ref.def_id())
662-
.filter(|item| item.kind == ty::AssociatedKind::Method);
663-
664-
// Now list each method's DefId and Substs (for within its trait).
665-
// If the method can never be called from this object, produce None.
666-
trait_methods.map(move |trait_method| {
667-
debug!("get_vtable_methods: trait_method={:?}", trait_method);
668-
let def_id = trait_method.def_id;
669-
670-
// Some methods cannot be called on an object; skip those.
671-
if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
672-
debug!("get_vtable_methods: not vtable safe");
673-
return None;
674-
}
675-
676-
// the method may have some early-bound lifetimes, add
677-
// regions for those
678-
let substs = Substs::for_item(tcx, def_id,
679-
|_, _| tcx.types.re_erased,
680-
|def, _| trait_ref.substs().type_for_def(def));
681-
682-
// the trait type may have higher-ranked lifetimes in it;
683-
// so erase them if they appear, so that we get the type
684-
// at some particular call site
685-
let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs));
686-
687-
// It's possible that the method relies on where clauses that
688-
// do not hold for this particular set of type parameters.
689-
// Note that this method could then never be called, so we
690-
// do not want to try and trans it, in that case (see #23435).
691-
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
692-
if !normalize_and_test_predicates(tcx, predicates.predicates) {
693-
debug!("get_vtable_methods: predicates do not hold");
694-
return None;
695-
}
696-
697-
Some((def_id, substs))
698-
})
699-
})
658+
debug!("vtable_methods({:?})", trait_ref);
659+
660+
Rc::new(
661+
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
662+
let trait_methods = tcx.associated_items(trait_ref.def_id())
663+
.filter(|item| item.kind == ty::AssociatedKind::Method);
664+
665+
// Now list each method's DefId and Substs (for within its trait).
666+
// If the method can never be called from this object, produce None.
667+
trait_methods.map(move |trait_method| {
668+
debug!("vtable_methods: trait_method={:?}", trait_method);
669+
let def_id = trait_method.def_id;
670+
671+
// Some methods cannot be called on an object; skip those.
672+
if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
673+
debug!("vtable_methods: not vtable safe");
674+
return None;
675+
}
676+
677+
// the method may have some early-bound lifetimes, add
678+
// regions for those
679+
let substs = Substs::for_item(tcx, def_id,
680+
|_, _| tcx.types.re_erased,
681+
|def, _| trait_ref.substs().type_for_def(def));
682+
683+
// the trait type may have higher-ranked lifetimes in it;
684+
// so erase them if they appear, so that we get the type
685+
// at some particular call site
686+
let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs));
687+
688+
// It's possible that the method relies on where clauses that
689+
// do not hold for this particular set of type parameters.
690+
// Note that this method could then never be called, so we
691+
// do not want to try and trans it, in that case (see #23435).
692+
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
693+
if !normalize_and_test_predicates(tcx, predicates.predicates) {
694+
debug!("vtable_methods: predicates do not hold");
695+
return None;
696+
}
697+
698+
Some((def_id, substs))
699+
})
700+
}).collect()
701+
)
700702
}
701703

702704
impl<'tcx,O> Obligation<'tcx,O> {
@@ -836,6 +838,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
836838
specialization_graph_of: specialize::specialization_graph_provider,
837839
specializes: specialize::specializes,
838840
trans_fulfill_obligation: trans::trans_fulfill_obligation,
841+
vtable_methods,
839842
..*providers
840843
};
841844
}
@@ -846,6 +849,7 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) {
846849
specialization_graph_of: specialize::specialization_graph_provider,
847850
specializes: specialize::specializes,
848851
trans_fulfill_obligation: trans::trans_fulfill_obligation,
852+
vtable_methods,
849853
..*providers
850854
};
851855
}

‎src/librustc/ty/maps/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,12 @@ impl<'tcx> QueryDescription for queries::has_clone_closures<'tcx> {
503503
}
504504
}
505505

506+
impl<'tcx> QueryDescription for queries::vtable_methods<'tcx> {
507+
fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String {
508+
format!("finding all methods for trait {}", tcx.item_path_str(key.def_id()))
509+
}
510+
}
511+
506512
impl<'tcx> QueryDescription for queries::has_copy_closures<'tcx> {
507513
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
508514
format!("seeing if the crate has enabled `Copy` closures")

‎src/librustc/ty/maps/keys.rs

+9
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,15 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
143143
}
144144
}
145145

146+
impl<'tcx> Key for ty::PolyTraitRef<'tcx>{
147+
fn map_crate(&self) -> CrateNum {
148+
self.def_id().krate
149+
}
150+
fn default_span(&self, tcx: TyCtxt) -> Span {
151+
tcx.def_span(self.def_id())
152+
}
153+
}
154+
146155
impl<'tcx> Key for Ty<'tcx> {
147156
fn map_crate(&self) -> CrateNum {
148157
LOCAL_CRATE

‎src/librustc/ty/maps/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ define_maps! { <'tcx>
228228
[] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies,
229229
[] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
230230
[] fn is_mir_available: IsMirAvailable(DefId) -> bool,
231+
[] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>)
232+
-> Rc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>,
231233

232234
[] fn trans_fulfill_obligation: fulfill_obligation_dep_node(
233235
(ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>,
@@ -470,3 +472,7 @@ fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstru
470472
fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
471473
DepConstructor::OutputFilenames
472474
}
475+
476+
fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> {
477+
DepConstructor::VtableMethods{ trait_ref }
478+
}

‎src/librustc/ty/maps/plumbing.rs

+5-99
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,7 @@ macro_rules! define_maps {
468468

469469
define_provider_struct! {
470470
tcx: $tcx,
471-
input: ($(([$($modifiers)*] [$name] [$K] [$V]))*),
472-
output: ()
471+
input: ($(([$($modifiers)*] [$name] [$K] [$V]))*)
473472
}
474473

475474
impl<$tcx> Copy for Providers<$tcx> {}
@@ -480,78 +479,19 @@ macro_rules! define_maps {
480479
}
481480

482481
macro_rules! define_map_struct {
483-
// Initial state
484482
(tcx: $tcx:tt,
485-
input: $input:tt) => {
486-
define_map_struct! {
487-
tcx: $tcx,
488-
input: $input,
489-
output: ()
490-
}
491-
};
492-
493-
// Final output
494-
(tcx: $tcx:tt,
495-
input: (),
496-
output: ($($output:tt)*)) => {
483+
input: ($(([$(modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
497484
pub struct Maps<$tcx> {
498485
providers: IndexVec<CrateNum, Providers<$tcx>>,
499486
query_stack: RefCell<Vec<(Span, Query<$tcx>)>>,
500-
$($output)*
501-
}
502-
};
503-
504-
// Field recognized and ready to shift into the output
505-
(tcx: $tcx:tt,
506-
ready: ([$($pub:tt)*] [$($attr:tt)*] [$name:ident]),
507-
input: $input:tt,
508-
output: ($($output:tt)*)) => {
509-
define_map_struct! {
510-
tcx: $tcx,
511-
input: $input,
512-
output: ($($output)*
513-
$(#[$attr])* $($pub)* $name: RefCell<QueryMap<queries::$name<$tcx>>>,)
514-
}
515-
};
516-
517-
// No modifiers left? This is a private item.
518-
(tcx: $tcx:tt,
519-
input: (([] $attrs:tt $name:tt) $($input:tt)*),
520-
output: $output:tt) => {
521-
define_map_struct! {
522-
tcx: $tcx,
523-
ready: ([] $attrs $name),
524-
input: ($($input)*),
525-
output: $output
526-
}
527-
};
528-
529-
// Skip other modifiers
530-
(tcx: $tcx:tt,
531-
input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*),
532-
output: $output:tt) => {
533-
define_map_struct! {
534-
tcx: $tcx,
535-
input: (([$($modifiers)*] $($fields)*) $($input)*),
536-
output: $output
487+
$($(#[$attr])* $name: RefCell<QueryMap<queries::$name<$tcx>>>,)*
537488
}
538489
};
539490
}
540491

541492
macro_rules! define_provider_struct {
542-
// Initial state:
543-
(tcx: $tcx:tt, input: $input:tt) => {
544-
define_provider_struct! {
545-
tcx: $tcx,
546-
input: $input,
547-
output: ()
548-
}
549-
};
550-
551-
// Final state:
552493
(tcx: $tcx:tt,
553-
input: (),
554-
output: ($(([$name:ident] [$K:ty] [$R:ty]))*)) => {
494+
input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => {
555495
pub struct Providers<$tcx> {
556496
$(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)*
557497
}
@@ -566,41 +506,6 @@ macro_rules! define_provider_struct {
566506
}
567507
}
568508
};
569-
570-
// Something ready to shift:
571-
(tcx: $tcx:tt,
572-
ready: ($name:tt $K:tt $V:tt),
573-
input: $input:tt,
574-
output: ($($output:tt)*)) => {
575-
define_provider_struct! {
576-
tcx: $tcx,
577-
input: $input,
578-
output: ($($output)* ($name $K $V))
579-
}
580-
};
581-
582-
// Regular queries produce a `V` only.
583-
(tcx: $tcx:tt,
584-
input: (([] $name:tt $K:tt $V:tt) $($input:tt)*),
585-
output: $output:tt) => {
586-
define_provider_struct! {
587-
tcx: $tcx,
588-
ready: ($name $K $V),
589-
input: ($($input)*),
590-
output: $output
591-
}
592-
};
593-
594-
// Skip modifiers.
595-
(tcx: $tcx:tt,
596-
input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*),
597-
output: $output:tt) => {
598-
define_provider_struct! {
599-
tcx: $tcx,
600-
input: (([$($modifiers)*] $($fields)*) $($input)*),
601-
output: $output
602-
}
603-
};
604509
}
605510

606511

@@ -749,6 +654,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
749654
DepKind::CodegenUnit |
750655
DepKind::CompileCodegenUnit |
751656
DepKind::FulfillObligation |
657+
DepKind::VtableMethods |
752658

753659
// These are just odd
754660
DepKind::Null |

‎src/librustc_trans/collector.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -849,8 +849,8 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
849849
assert!(!poly_trait_ref.has_escaping_regions());
850850

851851
// Walk all methods of the trait, including those of its supertraits
852-
let methods = traits::get_vtable_methods(tcx, poly_trait_ref);
853-
let methods = methods.filter_map(|method| method)
852+
let methods = tcx.vtable_methods(poly_trait_ref);
853+
let methods = methods.iter().cloned().filter_map(|method| method)
854854
.map(|(def_id, substs)| ty::Instance::resolve(
855855
tcx,
856856
ty::ParamEnv::empty(traits::Reveal::All),

‎src/librustc_trans/meth.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// except according to those terms.
1010

1111
use llvm::ValueRef;
12-
use rustc::traits;
1312
use callee;
1413
use common::*;
1514
use builder::Builder;
@@ -87,7 +86,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
8786

8887
if let Some(trait_ref) = trait_ref {
8988
let trait_ref = trait_ref.with_self_ty(tcx, ty);
90-
let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
89+
let methods = tcx.vtable_methods(trait_ref);
90+
let methods = methods.iter().cloned().map(|opt_mth| {
9191
opt_mth.map_or(nullptr, |(def_id, substs)| {
9292
callee::resolve_and_get_fn(ccx, def_id, substs)
9393
})

0 commit comments

Comments
 (0)
Please sign in to comment.