Skip to content

Commit 2336406

Browse files
committed
Auto merge of #86291 - crlf0710:trait_vtbl_refactor, r=bjorn3
Refactor vtable codegen This refactor the codegen of vtables of miri interpreter, llvm, cranelift codegen backends. This is preparation for the implementation of trait upcasting feature. cc #65991 Note that aside from code reorganization, there's an internal behavior change here that now InstanceDef::Virtual's index now include the three metadata slots, and now the first method is with index 3. cc `@RalfJung` `@bjorn3`
2 parents 52b2286 + a86d3a7 commit 2336406

File tree

10 files changed

+248
-179
lines changed

10 files changed

+248
-179
lines changed

compiler/rustc_codegen_cranelift/src/vtable.rs

+38-34
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
// FIXME dedup this logic between miri, cg_llvm and cg_clif
55

66
use crate::prelude::*;
7-
8-
const DROP_FN_INDEX: usize = 0;
9-
const SIZE_INDEX: usize = 1;
10-
const ALIGN_INDEX: usize = 2;
7+
use ty::VtblEntry;
118

129
fn vtable_memflags() -> MemFlags {
1310
let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
@@ -21,7 +18,7 @@ pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) ->
2118
pointer_ty(fx.tcx),
2219
vtable_memflags(),
2320
vtable,
24-
(DROP_FN_INDEX * usize_size) as i32,
21+
(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE * usize_size) as i32,
2522
)
2623
}
2724

@@ -31,7 +28,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val
3128
pointer_ty(fx.tcx),
3229
vtable_memflags(),
3330
vtable,
34-
(SIZE_INDEX * usize_size) as i32,
31+
(ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
3532
)
3633
}
3734

@@ -41,7 +38,7 @@ pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -
4138
pointer_ty(fx.tcx),
4239
vtable_memflags(),
4340
vtable,
44-
(ALIGN_INDEX * usize_size) as i32,
41+
(ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
4542
)
4643
}
4744

@@ -62,7 +59,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
6259
pointer_ty(fx.tcx),
6360
vtable_memflags(),
6461
vtable,
65-
((idx + 3) * usize_size as usize) as i32,
62+
(idx * usize_size as usize) as i32,
6663
);
6764
(ptr, func_ref)
6865
}
@@ -98,42 +95,49 @@ fn build_vtable<'tcx>(
9895
Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
9996
);
10097

101-
let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None];
102-
103-
let methods_root;
104-
let methods = if let Some(trait_ref) = trait_ref {
105-
methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, layout.ty));
106-
methods_root.iter()
98+
let vtable_entries = if let Some(trait_ref) = trait_ref {
99+
tcx.vtable_entries(trait_ref.with_self_ty(tcx, layout.ty))
107100
} else {
108-
(&[]).iter()
101+
ty::COMMON_VTABLE_ENTRIES
109102
};
110-
let methods = methods.cloned().map(|opt_mth| {
111-
opt_mth.map(|(def_id, substs)| {
112-
import_function(
113-
tcx,
114-
fx.module,
115-
Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs)
116-
.unwrap()
117-
.polymorphize(fx.tcx),
118-
)
119-
})
120-
});
121-
components.extend(methods);
122103

123104
let mut data_ctx = DataContext::new();
124105
let mut data = ::std::iter::repeat(0u8)
125-
.take(components.len() * usize_size)
106+
.take(vtable_entries.len() * usize_size)
126107
.collect::<Vec<u8>>()
127108
.into_boxed_slice();
128109

129-
write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes());
130-
write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes());
110+
for (idx, entry) in vtable_entries.iter().enumerate() {
111+
match entry {
112+
VtblEntry::MetadataSize => {
113+
write_usize(fx.tcx, &mut data, idx, layout.size.bytes());
114+
}
115+
VtblEntry::MetadataAlign => {
116+
write_usize(fx.tcx, &mut data, idx, layout.align.abi.bytes());
117+
}
118+
VtblEntry::MetadataDropInPlace | VtblEntry::Vacant | VtblEntry::Method(_, _) => {}
119+
}
120+
}
131121
data_ctx.define(data);
132122

133-
for (i, component) in components.into_iter().enumerate() {
134-
if let Some(func_id) = component {
135-
let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
136-
data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
123+
for (idx, entry) in vtable_entries.iter().enumerate() {
124+
match entry {
125+
VtblEntry::MetadataDropInPlace => {
126+
let func_ref = fx.module.declare_func_in_data(drop_in_place_fn, &mut data_ctx);
127+
data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
128+
}
129+
VtblEntry::Method(def_id, substs) => {
130+
let func_id = import_function(
131+
tcx,
132+
fx.module,
133+
Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), *def_id, substs)
134+
.unwrap()
135+
.polymorphize(fx.tcx),
136+
);
137+
let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
138+
data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
139+
}
140+
VtblEntry::MetadataSize | VtblEntry::MetadataAlign | VtblEntry::Vacant => {}
137141
}
138142
}
139143

compiler/rustc_codegen_ssa/src/glue.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
2323
ty::Dynamic(..) => {
2424
// load size/align from vtable
2525
let vtable = info.unwrap();
26-
(meth::SIZE.get_usize(bx, vtable), meth::ALIGN.get_usize(bx, vtable))
26+
(
27+
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE)
28+
.get_usize(bx, vtable),
29+
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
30+
.get_usize(bx, vtable),
31+
)
2732
}
2833
ty::Slice(_) | ty::Str => {
2934
let unit = layout.field(bx, 0);

compiler/rustc_codegen_ssa/src/meth.rs

+23-32
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
use crate::traits::*;
22

3-
use rustc_middle::ty::{self, Instance, Ty};
3+
use rustc_middle::ty::{self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES};
44
use rustc_target::abi::call::FnAbi;
55

66
#[derive(Copy, Clone, Debug)]
77
pub struct VirtualIndex(u64);
88

9-
pub const DESTRUCTOR: VirtualIndex = VirtualIndex(0);
10-
pub const SIZE: VirtualIndex = VirtualIndex(1);
11-
pub const ALIGN: VirtualIndex = VirtualIndex(2);
12-
139
impl<'a, 'tcx> VirtualIndex {
1410
pub fn from_index(index: usize) -> Self {
15-
VirtualIndex(index as u64 + 3)
11+
VirtualIndex(index as u64)
1612
}
1713

1814
pub fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
@@ -77,43 +73,38 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
7773
// Not in the cache; build it.
7874
let nullptr = cx.const_null(cx.type_i8p_ext(cx.data_layout().instruction_address_space));
7975

80-
let methods_root;
81-
let methods = if let Some(trait_ref) = trait_ref {
82-
methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
83-
methods_root.iter()
76+
let vtable_entries = if let Some(trait_ref) = trait_ref {
77+
tcx.vtable_entries(trait_ref.with_self_ty(tcx, ty))
8478
} else {
85-
(&[]).iter()
79+
COMMON_VTABLE_ENTRIES
8680
};
8781

88-
let methods = methods.cloned().map(|opt_mth| {
89-
opt_mth.map_or(nullptr, |(def_id, substs)| {
90-
cx.get_fn_addr(
82+
let layout = cx.layout_of(ty);
83+
// /////////////////////////////////////////////////////////////////////////////////////////////
84+
// If you touch this code, be sure to also make the corresponding changes to
85+
// `get_vtable` in `rust_mir/interpret/traits.rs`.
86+
// /////////////////////////////////////////////////////////////////////////////////////////////
87+
let components: Vec<_> = vtable_entries
88+
.iter()
89+
.map(|entry| match entry {
90+
VtblEntry::MetadataDropInPlace => {
91+
cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty))
92+
}
93+
VtblEntry::MetadataSize => cx.const_usize(layout.size.bytes()),
94+
VtblEntry::MetadataAlign => cx.const_usize(layout.align.abi.bytes()),
95+
VtblEntry::Vacant => nullptr,
96+
VtblEntry::Method(def_id, substs) => cx.get_fn_addr(
9197
ty::Instance::resolve_for_vtable(
9298
cx.tcx(),
9399
ty::ParamEnv::reveal_all(),
94-
def_id,
100+
*def_id,
95101
substs,
96102
)
97103
.unwrap()
98104
.polymorphize(cx.tcx()),
99-
)
105+
),
100106
})
101-
});
102-
103-
let layout = cx.layout_of(ty);
104-
// /////////////////////////////////////////////////////////////////////////////////////////////
105-
// If you touch this code, be sure to also make the corresponding changes to
106-
// `get_vtable` in `rust_mir/interpret/traits.rs`.
107-
// /////////////////////////////////////////////////////////////////////////////////////////////
108-
let components: Vec<_> = [
109-
cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty)),
110-
cx.const_usize(layout.size.bytes()),
111-
cx.const_usize(layout.align.abi.bytes()),
112-
]
113-
.iter()
114-
.cloned()
115-
.chain(methods)
116-
.collect();
107+
.collect();
117108

118109
let vtable_const = cx.const_struct(&components, false);
119110
let align = cx.data_layout().pointer_align.abi;

compiler/rustc_codegen_ssa/src/mir/block.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
332332
let fn_abi = FnAbi::of_instance(&bx, virtual_drop, &[]);
333333
let vtable = args[1];
334334
args = &args[..1];
335-
(meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_abi), fn_abi)
335+
(
336+
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
337+
.get_fn(&mut bx, vtable, &fn_abi),
338+
fn_abi,
339+
)
336340
}
337341
_ => (bx.get_fn_addr(drop_fn), FnAbi::of_instance(&bx, drop_fn, &[])),
338342
};

compiler/rustc_middle/src/query/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -959,9 +959,9 @@ rustc_queries! {
959959
desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
960960
}
961961

962-
query vtable_methods(key: ty::PolyTraitRef<'tcx>)
963-
-> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
964-
desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) }
962+
query vtable_entries(key: ty::PolyTraitRef<'tcx>)
963+
-> &'tcx [ty::VtblEntry<'tcx>] {
964+
desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
965965
}
966966

967967
query codegen_fulfill_obligation(

compiler/rustc_middle/src/ty/mod.rs

+16
Original file line numberDiff line numberDiff line change
@@ -2009,3 +2009,19 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
20092009
fmt::Display::fmt(&self.name, fmt)
20102010
}
20112011
}
2012+
2013+
#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
2014+
pub enum VtblEntry<'tcx> {
2015+
MetadataDropInPlace,
2016+
MetadataSize,
2017+
MetadataAlign,
2018+
Vacant,
2019+
Method(DefId, SubstsRef<'tcx>),
2020+
}
2021+
2022+
pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
2023+
&[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
2024+
2025+
pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
2026+
pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
2027+
pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;

0 commit comments

Comments
 (0)