2024-04-29 13:56:41 +10:00
|
|
|
use rustc_middle::bug;
|
2023-07-11 22:35:29 +01:00
|
|
|
use rustc_middle::ty::{self, GenericArgKind, Ty};
|
2022-04-21 13:58:25 +01:00
|
|
|
use rustc_session::config::Lto;
|
|
|
|
use rustc_symbol_mangling::typeid_for_trait_ref;
|
2024-11-02 19:32:52 -07:00
|
|
|
use rustc_target::callconv::FnAbi;
|
2024-05-22 15:08:26 +10:00
|
|
|
use tracing::{debug, instrument};
|
2012-08-28 15:54:45 -07:00
|
|
|
|
2019-02-09 23:31:47 +09:00
|
|
|
use crate::traits::*;
|
2024-07-29 08:13:50 +10:00
|
|
|
|
2017-03-14 01:08:21 +02:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2024-09-05 15:16:55 +10:00
|
|
|
pub(crate) struct VirtualIndex(u64);
|
2017-03-14 01:08:21 +02:00
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
impl<'a, 'tcx> VirtualIndex {
|
2024-09-05 15:16:55 +10:00
|
|
|
pub(crate) fn from_index(index: usize) -> Self {
|
2021-06-14 18:02:53 +08:00
|
|
|
VirtualIndex(index as u64)
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
|
|
|
|
2024-03-17 17:42:37 -04:00
|
|
|
fn get_fn_inner<Bx: BuilderMethods<'a, 'tcx>>(
|
2018-09-20 15:47:22 +02:00
|
|
|
self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2018-09-20 15:47:22 +02:00
|
|
|
llvtable: Bx::Value,
|
2022-04-21 13:58:25 +01:00
|
|
|
ty: Ty<'tcx>,
|
2019-05-17 02:20:14 +01:00
|
|
|
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
2024-03-17 17:42:37 -04:00
|
|
|
nonnull: bool,
|
2018-09-20 15:47:22 +02:00
|
|
|
) -> Bx::Value {
|
2024-03-10 22:38:53 -04:00
|
|
|
// Load the function pointer from the object.
|
2022-04-21 13:58:25 +01:00
|
|
|
debug!("get_fn({llvtable:?}, {ty:?}, {self:?})");
|
2024-03-10 22:38:53 -04:00
|
|
|
|
2021-07-04 18:53:04 +02:00
|
|
|
let llty = bx.fn_ptr_backend_type(fn_abi);
|
2024-03-10 22:38:53 -04:00
|
|
|
let ptr_size = bx.data_layout().pointer_size;
|
|
|
|
let vtable_byte_offset = self.0 * ptr_size.bytes();
|
2022-04-21 13:58:25 +01:00
|
|
|
|
2024-09-23 15:25:52 +08:00
|
|
|
load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, nonnull)
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
|
|
|
|
2024-09-05 15:16:55 +10:00
|
|
|
pub(crate) fn get_optional_fn<Bx: BuilderMethods<'a, 'tcx>>(
|
2024-03-17 17:42:37 -04:00
|
|
|
self,
|
|
|
|
bx: &mut Bx,
|
|
|
|
llvtable: Bx::Value,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
|
|
|
) -> Bx::Value {
|
|
|
|
self.get_fn_inner(bx, llvtable, ty, fn_abi, false)
|
|
|
|
}
|
|
|
|
|
2024-09-05 15:16:55 +10:00
|
|
|
pub(crate) fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
|
2024-03-17 17:42:37 -04:00
|
|
|
self,
|
|
|
|
bx: &mut Bx,
|
|
|
|
llvtable: Bx::Value,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
|
|
|
) -> Bx::Value {
|
|
|
|
self.get_fn_inner(bx, llvtable, ty, fn_abi, true)
|
|
|
|
}
|
|
|
|
|
2024-09-05 15:16:55 +10:00
|
|
|
pub(crate) fn get_usize<Bx: BuilderMethods<'a, 'tcx>>(
|
2018-08-07 17:14:40 +02:00
|
|
|
self,
|
2018-10-05 15:08:49 +02:00
|
|
|
bx: &mut Bx,
|
2019-05-17 02:20:14 +01:00
|
|
|
llvtable: Bx::Value,
|
2024-09-23 15:25:52 +08:00
|
|
|
ty: Ty<'tcx>,
|
2018-09-14 17:48:57 +02:00
|
|
|
) -> Bx::Value {
|
2017-03-14 01:08:21 +02:00
|
|
|
// Load the data pointer from the object.
|
2018-07-10 13:28:39 +03:00
|
|
|
debug!("get_int({:?}, {:?})", llvtable, self);
|
2017-03-14 01:08:21 +02:00
|
|
|
|
2021-07-04 18:53:04 +02:00
|
|
|
let llty = bx.type_isize();
|
2024-03-10 22:38:53 -04:00
|
|
|
let ptr_size = bx.data_layout().pointer_size;
|
|
|
|
let vtable_byte_offset = self.0 * ptr_size.bytes();
|
|
|
|
|
2024-09-23 15:25:52 +08:00
|
|
|
load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, false)
|
2017-03-14 01:08:21 +02:00
|
|
|
}
|
2012-01-07 22:44:14 +01:00
|
|
|
}
|
|
|
|
|
2022-08-29 04:19:14 +00:00
|
|
|
/// This takes a valid `self` receiver type and extracts the principal trait
|
2024-09-23 15:25:52 +08:00
|
|
|
/// ref of the type. Return `None` if there is no principal trait.
|
|
|
|
fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> {
|
2022-04-21 13:58:25 +01:00
|
|
|
for arg in ty.peel_refs().walk() {
|
2023-04-19 14:13:22 +00:00
|
|
|
if let GenericArgKind::Type(ty) = arg.unpack()
|
|
|
|
&& let ty::Dynamic(data, _, _) = ty.kind()
|
|
|
|
{
|
2024-09-23 15:25:52 +08:00
|
|
|
return data.principal();
|
2022-04-21 13:58:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bug!("expected a `dyn Trait` ty, found {ty:?}")
|
|
|
|
}
|
|
|
|
|
2016-09-08 12:58:05 +02:00
|
|
|
/// Creates a dynamic vtable for the given type and vtable origin.
|
2013-05-15 17:38:52 -07:00
|
|
|
/// This is used only for objects.
|
2014-09-12 11:42:58 -04:00
|
|
|
///
|
2016-09-08 12:58:05 +02:00
|
|
|
/// The vtables are cached instead of created on every call.
|
|
|
|
///
|
2014-09-12 11:42:58 -04:00
|
|
|
/// The `trait_ref` encodes the erased self type. Hence if we are
|
2018-11-20 09:34:15 -05:00
|
|
|
/// making an object `Foo<dyn Trait>` from a value of type `Foo<T>`, then
|
2019-05-17 02:20:14 +01:00
|
|
|
/// `trait_ref` would map `T: Trait`.
|
2022-07-27 14:50:11 -07:00
|
|
|
#[instrument(level = "debug", skip(cx))]
|
2024-09-05 15:16:55 +10:00
|
|
|
pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
|
2018-09-13 14:58:19 +02:00
|
|
|
cx: &Cx,
|
2018-07-10 13:28:39 +03:00
|
|
|
ty: Ty<'tcx>,
|
2018-12-04 13:28:06 +02:00
|
|
|
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
2018-09-13 14:58:19 +02:00
|
|
|
) -> Cx::Value {
|
|
|
|
let tcx = cx.tcx();
|
2013-08-13 13:22:58 -07:00
|
|
|
|
|
|
|
// Check the cache.
|
2018-09-13 14:58:19 +02:00
|
|
|
if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) {
|
2016-10-17 19:00:20 -07:00
|
|
|
return val;
|
2013-08-13 13:22:58 -07:00
|
|
|
}
|
|
|
|
|
2021-10-07 11:29:01 +02:00
|
|
|
let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref));
|
2021-06-20 17:43:25 +08:00
|
|
|
let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory();
|
|
|
|
let vtable_const = cx.const_data_from_alloc(vtable_allocation);
|
2018-09-09 01:16:45 +03:00
|
|
|
let align = cx.data_layout().pointer_align.abi;
|
2018-09-10 16:28:47 +02:00
|
|
|
let vtable = cx.static_addr_of(vtable_const, align, Some("vtable"));
|
2013-12-18 17:00:56 -08:00
|
|
|
|
2024-03-30 12:01:57 +00:00
|
|
|
cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable);
|
2022-03-14 17:18:30 +01:00
|
|
|
cx.create_vtable_debuginfo(ty, trait_ref, vtable);
|
2018-09-13 14:58:19 +02:00
|
|
|
cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
|
2014-04-10 14:04:45 +03:00
|
|
|
vtable
|
2012-01-12 16:57:30 +01:00
|
|
|
}
|
2024-09-23 15:25:52 +08:00
|
|
|
|
|
|
|
/// Call this function whenever you need to load a vtable.
|
|
|
|
pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|
|
|
bx: &mut Bx,
|
|
|
|
llvtable: Bx::Value,
|
|
|
|
llty: Bx::Type,
|
|
|
|
vtable_byte_offset: u64,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
nonnull: bool,
|
|
|
|
) -> Bx::Value {
|
|
|
|
let ptr_align = bx.data_layout().pointer_align.abi;
|
|
|
|
|
|
|
|
if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
|
|
|
|
&& bx.cx().sess().lto() == Lto::Fat
|
|
|
|
{
|
|
|
|
if let Some(trait_ref) = dyn_trait_in_self(ty) {
|
|
|
|
let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap();
|
|
|
|
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
|
|
|
|
return func;
|
|
|
|
} else if nonnull {
|
|
|
|
bug!("load nonnull value from a vtable without a principal trait")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
|
|
|
|
let ptr = bx.load(llty, gep, ptr_align);
|
|
|
|
// VTable loads are invariant.
|
|
|
|
bx.set_invariant_load(ptr);
|
|
|
|
if nonnull {
|
|
|
|
bx.nonnull_metadata(ptr);
|
|
|
|
}
|
|
|
|
ptr
|
|
|
|
}
|