Skip to content

Commit 178f3ba

Browse files
committed
Auto merge of #55016 - oli-obk:vtables💥_vtables_everywhere, r=<try>
Deduplicate some code and compile-time values around vtables r? @RalfJung
2 parents e9e27e6 + fce7dc2 commit 178f3ba

File tree

7 files changed

+58
-37
lines changed

7 files changed

+58
-37
lines changed

src/librustc/traits/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,7 @@ fn substitute_normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
896896
fn vtable_methods<'a, 'tcx>(
897897
tcx: TyCtxt<'a, 'tcx, 'tcx>,
898898
trait_ref: ty::PolyTraitRef<'tcx>)
899-
-> Lrc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>
899+
-> Lrc<Vec<Option<ty::Instance<'tcx>>>>
900900
{
901901
debug!("vtable_methods({:?})", trait_ref);
902902

@@ -947,8 +947,12 @@ fn vtable_methods<'a, 'tcx>(
947947
debug!("vtable_methods: predicates do not hold");
948948
return None;
949949
}
950-
951-
Some((def_id, substs))
950+
Some(ty::Instance::resolve(
951+
tcx,
952+
ty::ParamEnv::reveal_all(),
953+
def_id,
954+
substs,
955+
).unwrap())
952956
})
953957
}).collect()
954958
)

src/librustc/ty/query/mod.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,10 @@ define_queries! { <'tcx>
354354
},
355355

356356
Other {
357+
/// List of methods on a vtable. The final vtable won't have holes where `None`, but will
358+
/// simply skip methods that aren't object safe
357359
[] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>)
358-
-> Lrc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>,
360+
-> Lrc<Vec<Option<ty::Instance<'tcx>>>>,
359361
},
360362

361363
Codegen {
@@ -369,16 +371,16 @@ define_queries! { <'tcx>
369371
-> Lrc<specialization_graph::Graph>,
370372
[] fn is_object_safe: ObjectSafety(DefId) -> bool,
371373

372-
// Get the ParameterEnvironment for a given item; this environment
373-
// will be in "user-facing" mode, meaning that it is suitabe for
374-
// type-checking etc, and it does not normalize specializable
375-
// associated types. This is almost always what you want,
376-
// unless you are doing MIR optimizations, in which case you
377-
// might want to use `reveal_all()` method to change modes.
374+
/// Get the ParameterEnvironment for a given item; this environment
375+
/// will be in "user-facing" mode, meaning that it is suitabe for
376+
/// type-checking etc, and it does not normalize specializable
377+
/// associated types. This is almost always what you want,
378+
/// unless you are doing MIR optimizations, in which case you
379+
/// might want to use `reveal_all()` method to change modes.
378380
[] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>,
379381

380-
// Trait selection queries. These are best used by invoking `ty.moves_by_default()`,
381-
// `ty.is_copy()`, etc, since that will prune the environment where possible.
382+
/// Trait selection queries. These are best used by invoking `ty.moves_by_default()`,
383+
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
382384
[] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
383385
[] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
384386
[] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,

src/librustc_codegen_llvm/meth.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ pub fn get_vtable(
8787
let nullptr = C_null(Type::i8p(cx));
8888

8989
let (size, align) = cx.size_and_align_of(ty);
90+
// /////////////////////////////////////////////////////////////////////////////////////////////
91+
// If you touch this code, be sure to also make the corresponding changes to
92+
// `get_vtable` in rust_mir/interpret/traits.rs
93+
// /////////////////////////////////////////////////////////////////////////////////////////////
9094
let mut components: Vec<_> = [
9195
callee::get_fn(cx, monomorphize::resolve_drop_in_place(cx.tcx, ty)),
9296
C_usize(cx, size.bytes()),
@@ -97,8 +101,8 @@ pub fn get_vtable(
97101
let trait_ref = trait_ref.with_self_ty(tcx, ty);
98102
let methods = tcx.vtable_methods(trait_ref);
99103
let methods = methods.iter().cloned().map(|opt_mth| {
100-
opt_mth.map_or(nullptr, |(def_id, substs)| {
101-
callee::resolve_and_get_fn(cx, def_id, substs)
104+
opt_mth.map_or(nullptr, |instance| {
105+
callee::get_fn(cx, instance)
102106
})
103107
});
104108
components.extend(methods);

src/librustc_mir/interpret/cast.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
326326
}
327327
(_, &ty::Dynamic(ref data, _)) => {
328328
// Initial cast from sized to dyn trait
329-
let trait_ref = data.principal().unwrap().with_self_ty(
330-
*self.tcx,
331-
src_pointee_ty,
332-
);
333-
let trait_ref = self.tcx.erase_regions(&trait_ref);
334-
let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
329+
let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
335330
let ptr = self.read_value(src)?.to_scalar_ptr()?;
336331
let val = Value::new_dyn_trait(ptr, vtable);
337332
self.write_value(val, dest)

src/librustc_mir/interpret/eval_context.rs

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use rustc::mir::interpret::{
2727
EvalResult, EvalErrorKind,
2828
truncate, sign_extend,
2929
};
30+
use rustc_data_structures::fx::FxHashMap;
3031

3132
use syntax::source_map::{self, Span};
3233

@@ -50,6 +51,9 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
5051

5152
/// The virtual call stack.
5253
pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag>>,
54+
55+
/// A cache for deduplicating vtables
56+
pub(super) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), AllocId>,
5357
}
5458

5559
/// A stack frame.
@@ -207,6 +211,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
207211
param_env,
208212
memory: Memory::new(tcx, memory_data),
209213
stack: Vec::new(),
214+
vtables: FxHashMap(),
210215
}
211216
}
212217

src/librustc_mir/interpret/traits.rs

+28-12
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,36 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
2424
pub fn get_vtable(
2525
&mut self,
2626
ty: Ty<'tcx>,
27-
trait_ref: ty::PolyTraitRef<'tcx>,
27+
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
2828
) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
29-
debug!("get_vtable(trait_ref={:?})", trait_ref);
29+
debug!("get_vtable(trait_ref={:?})", poly_trait_ref);
3030

31-
// FIXME: Cache this!
31+
let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));
3232

33-
let layout = self.layout_of(trait_ref.self_ty())?;
33+
if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
34+
return Ok(Pointer::from(vtable).with_default_tag());
35+
}
36+
37+
let trait_ref = poly_trait_ref.map(|trait_ref| {
38+
let trait_ref = trait_ref.with_self_ty(*self.tcx, ty);
39+
self.tcx.erase_regions(&trait_ref)
40+
});
41+
42+
let methods = trait_ref.map(|trait_ref| self.tcx.vtable_methods(trait_ref));
43+
44+
let layout = self.layout_of(ty)?;
3445
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
3546
let size = layout.size.bytes();
3647
let align = layout.align.abi();
3748

3849
let ptr_size = self.pointer_size();
3950
let ptr_align = self.tcx.data_layout.pointer_align;
40-
let methods = self.tcx.vtable_methods(trait_ref);
51+
// /////////////////////////////////////////////////////////////////////////////////////////
52+
// If you touch this code, be sure to also make the corresponding changes to
53+
// `get_vtable` in rust_codegen_llvm/meth.rs
54+
// /////////////////////////////////////////////////////////////////////////////////////////
4155
let vtable = self.memory.allocate(
42-
ptr_size * (3 + methods.len() as u64),
56+
ptr_size * (3 + methods.as_ref().map_or(0, |m| m.len() as u64)),
4357
ptr_align,
4458
MemoryKind::Vtable,
4559
)?;
@@ -54,16 +68,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
5468
self.memory.write_ptr_sized(align_ptr, ptr_align,
5569
Scalar::from_uint(align, ptr_size).into())?;
5670

57-
for (i, method) in methods.iter().enumerate() {
58-
if let Some((def_id, substs)) = *method {
59-
let instance = self.resolve(def_id, substs)?;
60-
let fn_ptr = self.memory.create_fn_alloc(instance);
61-
let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &self)?;
62-
self.memory.write_ptr_sized(method_ptr, ptr_align, Scalar::Ptr(fn_ptr).into())?;
71+
if let Some(methods) = methods {
72+
for (i, method) in methods.iter().enumerate() {
73+
if let Some(instance) = *method {
74+
let fn_ptr = self.memory.create_fn_alloc(instance);
75+
let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &self)?;
76+
self.memory.write_ptr_sized(method_ptr, ptr_align, Scalar::Ptr(fn_ptr).into())?;
77+
}
6378
}
6479
}
6580

6681
self.memory.mark_immutable(vtable.alloc_id)?;
82+
assert!(self.vtables.insert((ty, poly_trait_ref), vtable.alloc_id).is_none());
6783

6884
Ok(vtable)
6985
}

src/librustc_mir/monomorphize/collector.rs

-5
Original file line numberDiff line numberDiff line change
@@ -914,11 +914,6 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
914914
// Walk all methods of the trait, including those of its supertraits
915915
let methods = tcx.vtable_methods(poly_trait_ref);
916916
let methods = methods.iter().cloned().filter_map(|method| method)
917-
.map(|(def_id, substs)| ty::Instance::resolve(
918-
tcx,
919-
ty::ParamEnv::reveal_all(),
920-
def_id,
921-
substs).unwrap())
922917
.filter(|&instance| should_monomorphize_locally(tcx, &instance))
923918
.map(|instance| create_fn_mono_item(instance));
924919
output.extend(methods);

0 commit comments

Comments
 (0)