]>
Commit | Line | Data |
---|---|---|
29967ef6 XL |
1 | //! Codegen vtables and vtable accesses. |
2 | //! | |
cdc7bbd5 | 3 | //! See `rustc_codegen_ssa/src/meth.rs` for reference. |
29967ef6 XL |
4 | // FIXME dedup this logic between miri, cg_llvm and cg_clif |
5 | ||
6 | use crate::prelude::*; | |
7 | ||
8 | const DROP_FN_INDEX: usize = 0; | |
9 | const SIZE_INDEX: usize = 1; | |
10 | const ALIGN_INDEX: usize = 2; | |
11 | ||
12 | fn vtable_memflags() -> MemFlags { | |
13 | let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap. | |
14 | flags.set_readonly(); // A vtable is always read-only. | |
15 | flags | |
16 | } | |
17 | ||
6a06907d | 18 | pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value { |
29967ef6 XL |
19 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; |
20 | fx.bcx.ins().load( | |
21 | pointer_ty(fx.tcx), | |
22 | vtable_memflags(), | |
23 | vtable, | |
24 | (DROP_FN_INDEX * usize_size) as i32, | |
25 | ) | |
26 | } | |
27 | ||
6a06907d | 28 | pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value { |
29967ef6 XL |
29 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; |
30 | fx.bcx.ins().load( | |
31 | pointer_ty(fx.tcx), | |
32 | vtable_memflags(), | |
33 | vtable, | |
34 | (SIZE_INDEX * usize_size) as i32, | |
35 | ) | |
36 | } | |
37 | ||
6a06907d | 38 | pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value { |
29967ef6 XL |
39 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; |
40 | fx.bcx.ins().load( | |
41 | pointer_ty(fx.tcx), | |
42 | vtable_memflags(), | |
43 | vtable, | |
44 | (ALIGN_INDEX * usize_size) as i32, | |
45 | ) | |
46 | } | |
47 | ||
48 | pub(crate) fn get_ptr_and_method_ref<'tcx>( | |
6a06907d | 49 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
29967ef6 XL |
50 | arg: CValue<'tcx>, |
51 | idx: usize, | |
52 | ) -> (Value, Value) { | |
53 | let (ptr, vtable) = if let Abi::ScalarPair(_, _) = arg.layout().abi { | |
54 | arg.load_scalar_pair(fx) | |
55 | } else { | |
56 | let (ptr, vtable) = arg.try_to_ptr().unwrap(); | |
57 | (ptr.get_addr(fx), vtable.unwrap()) | |
58 | }; | |
59 | ||
60 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes(); | |
61 | let func_ref = fx.bcx.ins().load( | |
62 | pointer_ty(fx.tcx), | |
63 | vtable_memflags(), | |
64 | vtable, | |
65 | ((idx + 3) * usize_size as usize) as i32, | |
66 | ); | |
67 | (ptr, func_ref) | |
68 | } | |
69 | ||
70 | pub(crate) fn get_vtable<'tcx>( | |
6a06907d | 71 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
29967ef6 XL |
72 | layout: TyAndLayout<'tcx>, |
73 | trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, | |
74 | ) -> Value { | |
17df50a5 | 75 | let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) { |
29967ef6 XL |
76 | *data_id |
77 | } else { | |
78 | let data_id = build_vtable(fx, layout, trait_ref); | |
17df50a5 | 79 | fx.vtables.insert((layout.ty, trait_ref), data_id); |
29967ef6 XL |
80 | data_id |
81 | }; | |
82 | ||
17df50a5 | 83 | let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); |
29967ef6 XL |
84 | fx.bcx.ins().global_value(fx.pointer_type, local_data_id) |
85 | } | |
86 | ||
87 | fn build_vtable<'tcx>( | |
6a06907d | 88 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
29967ef6 XL |
89 | layout: TyAndLayout<'tcx>, |
90 | trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, | |
91 | ) -> DataId { | |
92 | let tcx = fx.tcx; | |
93 | let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; | |
94 | ||
95 | let drop_in_place_fn = import_function( | |
96 | tcx, | |
17df50a5 | 97 | fx.module, |
29967ef6 XL |
98 | Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx), |
99 | ); | |
100 | ||
101 | let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None]; | |
102 | ||
103 | let methods_root; | |
104 | let methods = if let Some(trait_ref) = trait_ref { | |
105 | methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, layout.ty)); | |
106 | methods_root.iter() | |
107 | } else { | |
108 | (&[]).iter() | |
109 | }; | |
110 | let methods = methods.cloned().map(|opt_mth| { | |
111 | opt_mth.map(|(def_id, substs)| { | |
112 | import_function( | |
113 | tcx, | |
17df50a5 | 114 | fx.module, |
29967ef6 XL |
115 | Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs) |
116 | .unwrap() | |
117 | .polymorphize(fx.tcx), | |
118 | ) | |
119 | }) | |
120 | }); | |
121 | components.extend(methods); | |
122 | ||
123 | let mut data_ctx = DataContext::new(); | |
124 | let mut data = ::std::iter::repeat(0u8) | |
125 | .take(components.len() * usize_size) | |
126 | .collect::<Vec<u8>>() | |
127 | .into_boxed_slice(); | |
128 | ||
129 | write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes()); | |
130 | write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes()); | |
131 | data_ctx.define(data); | |
132 | ||
133 | for (i, component) in components.into_iter().enumerate() { | |
134 | if let Some(func_id) = component { | |
17df50a5 | 135 | let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx); |
29967ef6 XL |
136 | data_ctx.write_function_addr((i * usize_size) as u32, func_ref); |
137 | } | |
138 | } | |
139 | ||
140 | data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes()); | |
141 | ||
17df50a5 XL |
142 | let data_id = fx.module.declare_anonymous_data(false, false).unwrap(); |
143 | ||
144 | fx.module.define_data(data_id, &data_ctx).unwrap(); | |
29967ef6 XL |
145 | |
146 | data_id | |
147 | } | |
148 | ||
149 | fn write_usize(tcx: TyCtxt<'_>, buf: &mut [u8], idx: usize, num: u64) { | |
6a06907d XL |
150 | let pointer_size = |
151 | tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.usize)).unwrap().size.bytes() as usize; | |
29967ef6 XL |
152 | let target = &mut buf[idx * pointer_size..(idx + 1) * pointer_size]; |
153 | ||
154 | match tcx.data_layout.endian { | |
155 | rustc_target::abi::Endian::Little => match pointer_size { | |
156 | 4 => target.copy_from_slice(&(num as u32).to_le_bytes()), | |
157 | 8 => target.copy_from_slice(&(num as u64).to_le_bytes()), | |
158 | _ => todo!("pointer size {} is not yet supported", pointer_size), | |
159 | }, | |
160 | rustc_target::abi::Endian::Big => match pointer_size { | |
161 | 4 => target.copy_from_slice(&(num as u32).to_be_bytes()), | |
162 | 8 => target.copy_from_slice(&(num as u64).to_be_bytes()), | |
163 | _ => todo!("pointer size {} is not yet supported", pointer_size), | |
164 | }, | |
165 | } | |
166 | } |