Skip to main content

rustc_codegen_ssa/
meth.rs

1use rustc_middle::bug;
2use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt};
3use rustc_session::config::Lto;
4use rustc_symbol_mangling::typeid_for_trait_ref;
5use rustc_target::callconv::FnAbi;
6use tracing::{debug, instrument};
7
8use crate::traits::*;
9
10#[derive(#[automatically_derived]
impl ::core::marker::Copy for VirtualIndex { }Copy, #[automatically_derived]
impl ::core::clone::Clone for VirtualIndex {
    #[inline]
    fn clone(&self) -> VirtualIndex {
        let _: ::core::clone::AssertParamIsClone<u64>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for VirtualIndex {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "VirtualIndex",
            &&self.0)
    }
}Debug)]
11pub(crate) struct VirtualIndex(u64);
12
13impl<'a, 'tcx> VirtualIndex {
14    pub(crate) fn from_index(index: usize) -> Self {
15        VirtualIndex(index as u64)
16    }
17
18    fn get_fn_inner<Bx: BuilderMethods<'a, 'tcx>>(
19        self,
20        bx: &mut Bx,
21        llvtable: Bx::Value,
22        ty: Ty<'tcx>,
23        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
24        nonnull: bool,
25    ) -> Bx::Value {
26        // Load the function pointer from the object.
27        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/meth.rs:27",
                        "rustc_codegen_ssa::meth", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/meth.rs"),
                        ::tracing_core::__macro_support::Option::Some(27u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::meth"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("get_fn({0:?}, {1:?}, {2:?})",
                                                    llvtable, ty, self) as &dyn Value))])
            });
    } else { ; }
};debug!("get_fn({llvtable:?}, {ty:?}, {self:?})");
28
29        let llty = bx.fn_ptr_backend_type(fn_abi);
30        let ptr_size = bx.data_layout().pointer_size();
31        let vtable_byte_offset = self.0 * ptr_size.bytes();
32
33        load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, nonnull)
34    }
35
36    pub(crate) fn get_optional_fn<Bx: BuilderMethods<'a, 'tcx>>(
37        self,
38        bx: &mut Bx,
39        llvtable: Bx::Value,
40        ty: Ty<'tcx>,
41        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
42    ) -> Bx::Value {
43        self.get_fn_inner(bx, llvtable, ty, fn_abi, false)
44    }
45
46    pub(crate) fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
47        self,
48        bx: &mut Bx,
49        llvtable: Bx::Value,
50        ty: Ty<'tcx>,
51        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
52    ) -> Bx::Value {
53        self.get_fn_inner(bx, llvtable, ty, fn_abi, true)
54    }
55
56    pub(crate) fn get_usize<Bx: BuilderMethods<'a, 'tcx>>(
57        self,
58        bx: &mut Bx,
59        llvtable: Bx::Value,
60        ty: Ty<'tcx>,
61    ) -> Bx::Value {
62        // Load the data pointer from the object.
63        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/meth.rs:63",
                        "rustc_codegen_ssa::meth", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/meth.rs"),
                        ::tracing_core::__macro_support::Option::Some(63u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::meth"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("get_int({0:?}, {1:?})",
                                                    llvtable, self) as &dyn Value))])
            });
    } else { ; }
};debug!("get_int({:?}, {:?})", llvtable, self);
64
65        let llty = bx.type_isize();
66        let ptr_size = bx.data_layout().pointer_size();
67        let vtable_byte_offset = self.0 * ptr_size.bytes();
68
69        load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, false)
70    }
71}
72
73/// This takes a valid `self` receiver type and extracts the principal trait
74/// ref of the type. Return `None` if there is no principal trait.
75fn dyn_trait_in_self<'tcx>(
76    tcx: TyCtxt<'tcx>,
77    ty: Ty<'tcx>,
78) -> Option<ty::ExistentialTraitRef<'tcx>> {
79    for arg in ty.peel_refs().walk() {
80        if let GenericArgKind::Type(ty) = arg.kind()
81            && let ty::Dynamic(data, _) = ty.kind()
82        {
83            // FIXME(arbitrary_self_types): This is likely broken for receivers which
84            // have a "non-self" trait objects as a generic argument.
85            return data
86                .principal()
87                .map(|principal| tcx.instantiate_bound_regions_with_erased(principal));
88        }
89    }
90
91    ::rustc_middle::util::bug::bug_fmt(format_args!("expected a `dyn Trait` ty, found {0:?}",
        ty))bug!("expected a `dyn Trait` ty, found {ty:?}")
92}
93
94/// Creates a dynamic vtable for the given type and vtable origin.
95/// This is used only for objects.
96///
97/// The vtables are cached instead of created on every call.
98///
99/// The `trait_ref` encodes the erased self type. Hence if we are
100/// making an object `Foo<dyn Trait>` from a value of type `Foo<T>`, then
101/// `trait_ref` would map `T: Trait`.
102#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("get_vtable",
                                    "rustc_codegen_ssa::meth", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/meth.rs"),
                                    ::tracing_core::__macro_support::Option::Some(102u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::meth"),
                                    ::tracing_core::field::FieldSet::new(&["ty", "trait_ref"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&trait_ref)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Cx::Value = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let tcx = cx.tcx();
            if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) {
                return val;
            }
            let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref));
            let vtable_allocation =
                tcx.global_alloc(vtable_alloc_id).unwrap_memory();
            let vtable_const = cx.const_data_from_alloc(vtable_allocation);
            let align = cx.data_layout().pointer_align().abi;
            let vtable =
                cx.static_addr_of(vtable_const, align, Some("vtable"));
            cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable);
            cx.create_vtable_debuginfo(ty, trait_ref, vtable);
            cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
            vtable
        }
    }
}#[instrument(level = "debug", skip(cx))]
103pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
104    cx: &Cx,
105    ty: Ty<'tcx>,
106    trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
107) -> Cx::Value {
108    let tcx = cx.tcx();
109
110    // Check the cache.
111    if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) {
112        return val;
113    }
114
115    let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref));
116    let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory();
117    let vtable_const = cx.const_data_from_alloc(vtable_allocation);
118    let align = cx.data_layout().pointer_align().abi;
119    let vtable = cx.static_addr_of(vtable_const, align, Some("vtable"));
120
121    cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable);
122    cx.create_vtable_debuginfo(ty, trait_ref, vtable);
123    cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
124    vtable
125}
126
127/// Call this function whenever you need to load a vtable.
128pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
129    bx: &mut Bx,
130    llvtable: Bx::Value,
131    llty: Bx::Type,
132    vtable_byte_offset: u64,
133    ty: Ty<'tcx>,
134    nonnull: bool,
135) -> Bx::Value {
136    let ptr_align = bx.data_layout().pointer_align().abi;
137
138    if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
139        && bx.cx().sess().lto() == Lto::Fat
140    {
141        if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) {
142            let typeid =
143                bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref).as_bytes()).unwrap();
144            let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
145            return func;
146        } else if nonnull {
147            ::rustc_middle::util::bug::bug_fmt(format_args!("load nonnull value from a vtable without a principal trait"))bug!("load nonnull value from a vtable without a principal trait")
148        }
149    }
150
151    let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
152    let ptr = bx.load(llty, gep, ptr_align);
153    // VTable loads are invariant.
154    bx.set_invariant_load(ptr);
155    if nonnull {
156        bx.nonnull_metadata(ptr);
157    }
158    ptr
159}