]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::traits::*; |
b7449926 | 2 | |
f2b60f7d | 3 | use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; |
923072b8 FG |
4 | use rustc_session::config::Lto; |
5 | use rustc_symbol_mangling::typeid_for_trait_ref; | |
60c5eb7d | 6 | use rustc_target::abi::call::FnAbi; |
54a0048b | 7 | |
cc61c64b | 8 | #[derive(Copy, Clone, Debug)] |
ff7c6d11 | 9 | pub struct VirtualIndex(u64); |
54a0048b | 10 | |
dc9dc135 | 11 | impl<'a, 'tcx> VirtualIndex { |
cc61c64b | 12 | pub fn from_index(index: usize) -> Self { |
136023e0 | 13 | VirtualIndex(index as u64) |
cc61c64b XL |
14 | } |
15 | ||
a1dfa0c6 XL |
16 | pub fn get_fn<Bx: BuilderMethods<'a, 'tcx>>( |
17 | self, | |
18 | bx: &mut Bx, | |
19 | llvtable: Bx::Value, | |
923072b8 | 20 | ty: Ty<'tcx>, |
60c5eb7d | 21 | fn_abi: &FnAbi<'tcx, Ty<'tcx>>, |
a1dfa0c6 | 22 | ) -> Bx::Value { |
cc61c64b | 23 | // Load the data pointer from the object. |
923072b8 | 24 | debug!("get_fn({llvtable:?}, {ty:?}, {self:?})"); |
136023e0 XL |
25 | let llty = bx.fn_ptr_backend_type(fn_abi); |
26 | let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty)); | |
923072b8 | 27 | |
064997fb | 28 | if bx.cx().sess().opts.unstable_opts.virtual_function_elimination |
923072b8 FG |
29 | && bx.cx().sess().lto() == Lto::Fat |
30 | { | |
49aad941 FG |
31 | let typeid = bx |
32 | .typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty))) | |
33 | .unwrap(); | |
923072b8 | 34 | let vtable_byte_offset = self.0 * bx.data_layout().pointer_size.bytes(); |
9c376795 | 35 | let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); |
923072b8 FG |
36 | bx.pointercast(func, llty) |
37 | } else { | |
38 | let ptr_align = bx.tcx().data_layout.pointer_align.abi; | |
39 | let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]); | |
40 | let ptr = bx.load(llty, gep, ptr_align); | |
41 | bx.nonnull_metadata(ptr); | |
064997fb | 42 | // VTable loads are invariant. |
923072b8 FG |
43 | bx.set_invariant_load(ptr); |
44 | ptr | |
45 | } | |
32a655c1 | 46 | } |
54a0048b | 47 | |
a1dfa0c6 XL |
48 | pub fn get_usize<Bx: BuilderMethods<'a, 'tcx>>( |
49 | self, | |
50 | bx: &mut Bx, | |
60c5eb7d | 51 | llvtable: Bx::Value, |
a1dfa0c6 | 52 | ) -> Bx::Value { |
cc61c64b | 53 | // Load the data pointer from the object. |
b7449926 | 54 | debug!("get_int({:?}, {:?})", llvtable, self); |
cc61c64b | 55 | |
136023e0 XL |
56 | let llty = bx.type_isize(); |
57 | let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty)); | |
a1dfa0c6 | 58 | let usize_align = bx.tcx().data_layout.pointer_align.abi; |
94222f64 | 59 | let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]); |
136023e0 | 60 | let ptr = bx.load(llty, gep, usize_align); |
064997fb | 61 | // VTable loads are invariant. |
2c00a5a8 | 62 | bx.set_invariant_load(ptr); |
cc61c64b XL |
63 | ptr |
64 | } | |
54a0048b SL |
65 | } |
66 | ||
f2b60f7d FG |
67 | /// This takes a valid `self` receiver type and extracts the principal trait |
68 | /// ref of the type. | |
9c376795 | 69 | fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> { |
923072b8 | 70 | for arg in ty.peel_refs().walk() { |
49aad941 FG |
71 | if let GenericArgKind::Type(ty) = arg.unpack() |
72 | && let ty::Dynamic(data, _, _) = ty.kind() | |
73 | { | |
74 | return data.principal().expect("expected principal trait object"); | |
923072b8 FG |
75 | } |
76 | } | |
77 | ||
78 | bug!("expected a `dyn Trait` ty, found {ty:?}") | |
79 | } | |
80 | ||
9e0c209e | 81 | /// Creates a dynamic vtable for the given type and vtable origin. |
54a0048b SL |
82 | /// This is used only for objects. |
83 | /// | |
9e0c209e SL |
84 | /// The vtables are cached instead of created on every call. |
85 | /// | |
54a0048b | 86 | /// The `trait_ref` encodes the erased self type. Hence if we are |
a1dfa0c6 | 87 | /// making an object `Foo<dyn Trait>` from a value of type `Foo<T>`, then |
60c5eb7d | 88 | /// `trait_ref` would map `T: Trait`. |
f2b60f7d | 89 | #[instrument(level = "debug", skip(cx))] |
a1dfa0c6 XL |
90 | pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( |
91 | cx: &Cx, | |
b7449926 | 92 | ty: Ty<'tcx>, |
0731742a | 93 | trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, |
a1dfa0c6 XL |
94 | ) -> Cx::Value { |
95 | let tcx = cx.tcx(); | |
54a0048b | 96 | |
54a0048b | 97 | // Check the cache. |
a1dfa0c6 | 98 | if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) { |
c30ab7b3 | 99 | return val; |
54a0048b SL |
100 | } |
101 | ||
dc3f5686 | 102 | let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref)); |
136023e0 XL |
103 | let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory(); |
104 | let vtable_const = cx.const_data_from_alloc(vtable_allocation); | |
a1dfa0c6 XL |
105 | let align = cx.data_layout().pointer_align.abi; |
106 | let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); | |
54a0048b | 107 | |
5e7ed085 | 108 | cx.create_vtable_debuginfo(ty, trait_ref, vtable); |
a1dfa0c6 | 109 | cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); |
54a0048b SL |
110 | vtable |
111 | } |