Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor vtable codegen #86291

Merged
merged 1 commit into from
Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 38 additions & 34 deletions compiler/rustc_codegen_cranelift/src/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
// FIXME dedup this logic between miri, cg_llvm and cg_clif

use crate::prelude::*;

const DROP_FN_INDEX: usize = 0;
const SIZE_INDEX: usize = 1;
const ALIGN_INDEX: usize = 2;
use ty::VtblEntry;

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

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

Expand All @@ -41,7 +38,7 @@ pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -
pointer_ty(fx.tcx),
vtable_memflags(),
vtable,
(ALIGN_INDEX * usize_size) as i32,
(ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
crlf0710 marked this conversation as resolved.
Show resolved Hide resolved
)
}

Expand All @@ -62,7 +59,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
pointer_ty(fx.tcx),
vtable_memflags(),
vtable,
((idx + 3) * usize_size as usize) as i32,
(idx * usize_size as usize) as i32,
);
(ptr, func_ref)
}
Expand Down Expand Up @@ -98,42 +95,49 @@ fn build_vtable<'tcx>(
Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
);

let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None];

let methods_root;
let methods = if let Some(trait_ref) = trait_ref {
methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, layout.ty));
methods_root.iter()
let vtable_entries = if let Some(trait_ref) = trait_ref {
tcx.vtable_entries(trait_ref.with_self_ty(tcx, layout.ty))
} else {
(&[]).iter()
ty::COMMON_VTABLE_ENTRIES
};
let methods = methods.cloned().map(|opt_mth| {
opt_mth.map(|(def_id, substs)| {
import_function(
tcx,
fx.module,
Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs)
.unwrap()
.polymorphize(fx.tcx),
)
})
});
components.extend(methods);

let mut data_ctx = DataContext::new();
let mut data = ::std::iter::repeat(0u8)
.take(components.len() * usize_size)
.take(vtable_entries.len() * usize_size)
.collect::<Vec<u8>>()
.into_boxed_slice();

write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes());
write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes());
for (idx, entry) in vtable_entries.iter().enumerate() {
match entry {
VtblEntry::MetadataSize => {
write_usize(fx.tcx, &mut data, idx, layout.size.bytes());
}
VtblEntry::MetadataAlign => {
write_usize(fx.tcx, &mut data, idx, layout.align.abi.bytes());
}
VtblEntry::MetadataDropInPlace | VtblEntry::Vacant | VtblEntry::Method(_, _) => {}
}
}
data_ctx.define(data);

for (i, component) in components.into_iter().enumerate() {
if let Some(func_id) = component {
let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
for (idx, entry) in vtable_entries.iter().enumerate() {
match entry {
VtblEntry::MetadataDropInPlace => {
let func_ref = fx.module.declare_func_in_data(drop_in_place_fn, &mut data_ctx);
data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
}
VtblEntry::Method(def_id, substs) => {
let func_id = import_function(
tcx,
fx.module,
Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), *def_id, substs)
.unwrap()
.polymorphize(fx.tcx),
);
let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
}
VtblEntry::MetadataSize | VtblEntry::MetadataAlign | VtblEntry::Vacant => {}
}
}

Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_codegen_ssa/src/glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
ty::Dynamic(..) => {
// load size/align from vtable
let vtable = info.unwrap();
(meth::SIZE.get_usize(bx, vtable), meth::ALIGN.get_usize(bx, vtable))
(
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE)
.get_usize(bx, vtable),
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
.get_usize(bx, vtable),
)
}
ty::Slice(_) | ty::Str => {
let unit = layout.field(bx, 0);
Expand Down
55 changes: 23 additions & 32 deletions compiler/rustc_codegen_ssa/src/meth.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
use crate::traits::*;

use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::ty::{self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES};
use rustc_target::abi::call::FnAbi;

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

pub const DESTRUCTOR: VirtualIndex = VirtualIndex(0);
pub const SIZE: VirtualIndex = VirtualIndex(1);
pub const ALIGN: VirtualIndex = VirtualIndex(2);

impl<'a, 'tcx> VirtualIndex {
pub fn from_index(index: usize) -> Self {
VirtualIndex(index as u64 + 3)
VirtualIndex(index as u64)
}

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

let methods_root;
let methods = if let Some(trait_ref) = trait_ref {
methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
methods_root.iter()
let vtable_entries = if let Some(trait_ref) = trait_ref {
tcx.vtable_entries(trait_ref.with_self_ty(tcx, ty))
} else {
(&[]).iter()
COMMON_VTABLE_ENTRIES
};

let methods = methods.cloned().map(|opt_mth| {
opt_mth.map_or(nullptr, |(def_id, substs)| {
cx.get_fn_addr(
let layout = cx.layout_of(ty);
// /////////////////////////////////////////////////////////////////////////////////////////////
// If you touch this code, be sure to also make the corresponding changes to
// `get_vtable` in `rust_mir/interpret/traits.rs`.
// /////////////////////////////////////////////////////////////////////////////////////////////
let components: Vec<_> = vtable_entries
.iter()
.map(|entry| match entry {
VtblEntry::MetadataDropInPlace => {
cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty))
}
VtblEntry::MetadataSize => cx.const_usize(layout.size.bytes()),
VtblEntry::MetadataAlign => cx.const_usize(layout.align.abi.bytes()),
VtblEntry::Vacant => nullptr,
VtblEntry::Method(def_id, substs) => cx.get_fn_addr(
ty::Instance::resolve_for_vtable(
cx.tcx(),
ty::ParamEnv::reveal_all(),
def_id,
*def_id,
substs,
)
.unwrap()
.polymorphize(cx.tcx()),
)
),
})
});

let layout = cx.layout_of(ty);
// /////////////////////////////////////////////////////////////////////////////////////////////
// If you touch this code, be sure to also make the corresponding changes to
// `get_vtable` in `rust_mir/interpret/traits.rs`.
// /////////////////////////////////////////////////////////////////////////////////////////////
let components: Vec<_> = [
cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty)),
cx.const_usize(layout.size.bytes()),
cx.const_usize(layout.align.abi.bytes()),
]
.iter()
.cloned()
.chain(methods)
.collect();
.collect();

let vtable_const = cx.const_struct(&components, false);
let align = cx.data_layout().pointer_align.abi;
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let fn_abi = FnAbi::of_instance(&bx, virtual_drop, &[]);
let vtable = args[1];
args = &args[..1];
(meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_abi), fn_abi)
(
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
.get_fn(&mut bx, vtable, &fn_abi),
fn_abi,
)
}
_ => (bx.get_fn_addr(drop_fn), FnAbi::of_instance(&bx, drop_fn, &[])),
};
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -959,9 +959,9 @@ rustc_queries! {
desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
}

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

query codegen_fulfill_obligation(
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2009,3 +2009,19 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
fmt::Display::fmt(&self.name, fmt)
}
}

#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
pub enum VtblEntry<'tcx> {
MetadataDropInPlace,
MetadataSize,
MetadataAlign,
Vacant,
Method(DefId, SubstsRef<'tcx>),
}

pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
&[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];

pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
Loading