Skip to main content

rustc_codegen_ssa/
meth.rs

1use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt};
2use rustc_session::config::Lto;
3use rustc_span::bug;
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]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for VirtualIndex {
}
#[automatically_derived]impl ::core::clone::Clone for VirtualIndex {
    #[inline]
    fn clone(&self) -> Self {
        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_struct_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    /// Load this index from the vtable.
19    fn load_field<Bx: BuilderMethods<'a, 'tcx>>(
20        self,
21        bx: &mut Bx,
22        llvtable: Bx::Value,
23        llty: Bx::Type,
24        nonnull: bool,
25    ) -> Bx::Value {
26        let ptr_size = bx.data_layout().pointer_size();
27        let vtable_byte_offset = self.0 * ptr_size.bytes();
28
29        let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
30        let ptr_align = bx.data_layout().pointer_align();
31        let ptr = bx.load(llty, gep, ptr_align);
32
33        // VTable loads are invariant.
34        bx.set_invariant_load(ptr);
35
36        if nonnull {
37            bx.nonnull_metadata(ptr);
38        }
39
40        ptr
41    }
42
43    fn get_fn_inner<Bx: BuilderMethods<'a, 'tcx>>(
44        self,
45        bx: &mut Bx,
46        llvtable: Bx::Value,
47        ty: Ty<'tcx>,
48        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
49        nonnull: bool,
50    ) -> Bx::Value {
51        // Load the function pointer from the object.
52        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/249c1e4e31111b54ad2483cfd4cea06c7020c653/compiler/rustc_codegen_ssa/src/meth.rs:52",
                        "rustc_codegen_ssa::meth", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/249c1e4e31111b54ad2483cfd4cea06c7020c653/compiler/rustc_codegen_ssa/src/meth.rs"),
                        ::tracing_core::__macro_support::Option::Some(52u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("get_fn({0:?}, {1:?}, {2:?})",
                                                    llvtable, ty, self) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("get_fn({llvtable:?}, {ty:?}, {self:?})");
53
54        let llty = bx.fn_ptr_backend_type(fn_abi);
55        let ptr_size = bx.data_layout().pointer_size();
56        let vtable_byte_offset = self.0 * ptr_size.bytes();
57
58        if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
59            && bx.cx().sess().lto() == Lto::Fat
60        {
61            if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) {
62                let typeid = typeid_for_trait_ref(bx.tcx(), trait_ref);
63                let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid.as_bytes());
64                return func;
65            } else if nonnull {
66                ::rustc_span::macros::bug_impl(None,
    format_args!("load nonnull value from a vtable without a principal trait"),
    Location::caller())bug!("load nonnull value from a vtable without a principal trait")
67            }
68        }
69
70        self.load_field(bx, llvtable, llty, nonnull)
71    }
72
73    pub(crate) fn get_optional_fn<Bx: BuilderMethods<'a, 'tcx>>(
74        self,
75        bx: &mut Bx,
76        llvtable: Bx::Value,
77        ty: Ty<'tcx>,
78        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
79    ) -> Bx::Value {
80        self.get_fn_inner(bx, llvtable, ty, fn_abi, false)
81    }
82
83    pub(crate) fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
84        self,
85        bx: &mut Bx,
86        llvtable: Bx::Value,
87        ty: Ty<'tcx>,
88        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
89    ) -> Bx::Value {
90        self.get_fn_inner(bx, llvtable, ty, fn_abi, true)
91    }
92
93    /// Read a data pointer. For function pointers, use [`VirtualIndex::get_fn`].
94    pub(crate) fn get_data_ptr<Bx: BuilderMethods<'a, 'tcx>>(
95        self,
96        bx: &mut Bx,
97        llvtable: Bx::Value,
98        nonnull: bool,
99    ) -> Bx::Value {
100        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/249c1e4e31111b54ad2483cfd4cea06c7020c653/compiler/rustc_codegen_ssa/src/meth.rs:100",
                        "rustc_codegen_ssa::meth", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/249c1e4e31111b54ad2483cfd4cea06c7020c653/compiler/rustc_codegen_ssa/src/meth.rs"),
                        ::tracing_core::__macro_support::Option::Some(100u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("get_data_ptr({0:?}, {1:?})",
                                                    llvtable, self) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("get_data_ptr({:?}, {:?})", llvtable, self);
101        self.load_field(bx, llvtable, bx.type_ptr(), nonnull)
102    }
103
104    pub(crate) fn get_usize<Bx: BuilderMethods<'a, 'tcx>>(
105        self,
106        bx: &mut Bx,
107        llvtable: Bx::Value,
108    ) -> Bx::Value {
109        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/249c1e4e31111b54ad2483cfd4cea06c7020c653/compiler/rustc_codegen_ssa/src/meth.rs:109",
                        "rustc_codegen_ssa::meth", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/249c1e4e31111b54ad2483cfd4cea06c7020c653/compiler/rustc_codegen_ssa/src/meth.rs"),
                        ::tracing_core::__macro_support::Option::Some(109u32),
                        ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("get_usize({0:?}, {1:?})",
                                                    llvtable, self) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("get_usize({:?}, {:?})", llvtable, self);
110        self.load_field(bx, llvtable, bx.type_isize(), false)
111    }
112}
113
114/// This takes a valid `self` receiver type and extracts the principal trait
115/// ref of the type. Return `None` if there is no principal trait.
116fn dyn_trait_in_self<'tcx>(
117    tcx: TyCtxt<'tcx>,
118    ty: Ty<'tcx>,
119) -> Option<ty::ExistentialTraitRef<'tcx>> {
120    for arg in ty.peel_refs().walk() {
121        if let GenericArgKind::Type(ty) = arg.kind()
122            && let ty::Dynamic(data, _) = ty.kind()
123        {
124            // FIXME(arbitrary_self_types): This is likely broken for receivers which
125            // have a "non-self" trait objects as a generic argument.
126            return data
127                .principal()
128                .map(|principal| tcx.instantiate_bound_regions_with_erased(principal));
129        }
130    }
131
132    ::rustc_span::macros::bug_impl(None,
    format_args!("expected a `dyn Trait` ty, found {0:?}", ty),
    Location::caller())bug!("expected a `dyn Trait` ty, found {ty:?}")
133}
134
135/// Creates a dynamic vtable for the given type and vtable origin.
136/// This is used only for objects.
137///
138/// The vtables are cached instead of created on every call.
139///
140/// The `trait_ref` encodes the erased self type. Hence if we are
141/// making an object `Foo<dyn Trait>` from a value of type `Foo<T>`, then
142/// `trait_ref` would map `T: Trait`.
143{}
#[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("/rustc-dev/249c1e4e31111b54ad2483cfd4cea06c7020c653/compiler/rustc_codegen_ssa/src/meth.rs"),
                                    ::tracing_core::__macro_support::Option::Some(143u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::meth"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("ty")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("ty");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("trait_ref")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("trait_ref");
                                                        NAME.as_str()
                                                    }], ::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};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&trait_ref)
                                                            as &dyn ::tracing::field::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 = cx.static_addr_of(vtable_allocation, 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))]
144pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
145    cx: &Cx,
146    ty: Ty<'tcx>,
147    trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
148) -> Cx::Value {
149    let tcx = cx.tcx();
150
151    // Check the cache.
152    if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) {
153        return val;
154    }
155
156    let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref));
157    let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory();
158    let vtable = cx.static_addr_of(vtable_allocation, Some("vtable"));
159
160    cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable);
161    cx.create_vtable_debuginfo(ty, trait_ref, vtable);
162    cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
163    vtable
164}