]>
git.proxmox.com Git - rustc.git/blob - compiler/rustc_codegen_cranelift/src/vtable.rs
1 //! Codegen vtables and vtable accesses.
3 //! See librustc_codegen_llvm/meth.rs for reference
4 // FIXME dedup this logic between miri, cg_llvm and cg_clif
8 const DROP_FN_INDEX
: usize = 0;
9 const SIZE_INDEX
: usize = 1;
10 const ALIGN_INDEX
: usize = 2;
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.
18 pub(crate) fn drop_fn_of_obj(fx
: &mut FunctionCx
<'_
, '_
, impl Module
>, vtable
: Value
) -> Value
{
19 let usize_size
= fx
.layout_of(fx
.tcx
.types
.usize).size
.bytes() as usize;
24 (DROP_FN_INDEX
* usize_size
) as i32,
28 pub(crate) fn size_of_obj(fx
: &mut FunctionCx
<'_
, '_
, impl Module
>, vtable
: Value
) -> Value
{
29 let usize_size
= fx
.layout_of(fx
.tcx
.types
.usize).size
.bytes() as usize;
34 (SIZE_INDEX
* usize_size
) as i32,
38 pub(crate) fn min_align_of_obj(fx
: &mut FunctionCx
<'_
, '_
, impl Module
>, vtable
: Value
) -> Value
{
39 let usize_size
= fx
.layout_of(fx
.tcx
.types
.usize).size
.bytes() as usize;
44 (ALIGN_INDEX
* usize_size
) as i32,
48 pub(crate) fn get_ptr_and_method_ref
<'tcx
>(
49 fx
: &mut FunctionCx
<'_
, 'tcx
, impl Module
>,
53 let (ptr
, vtable
) = if let Abi
::ScalarPair(_
, _
) = arg
.layout().abi
{
54 arg
.load_scalar_pair(fx
)
56 let (ptr
, vtable
) = arg
.try_to_ptr().unwrap();
57 (ptr
.get_addr(fx
), vtable
.unwrap())
60 let usize_size
= fx
.layout_of(fx
.tcx
.types
.usize).size
.bytes();
61 let func_ref
= fx
.bcx
.ins().load(
65 ((idx
+ 3) * usize_size
as usize) as i32,
70 pub(crate) fn get_vtable
<'tcx
>(
71 fx
: &mut FunctionCx
<'_
, 'tcx
, impl Module
>,
72 layout
: TyAndLayout
<'tcx
>,
73 trait_ref
: Option
<ty
::PolyExistentialTraitRef
<'tcx
>>,
75 let data_id
= if let Some(data_id
) = fx
.cx
.vtables
.get(&(layout
.ty
, trait_ref
)) {
78 let data_id
= build_vtable(fx
, layout
, trait_ref
);
79 fx
.cx
.vtables
.insert((layout
.ty
, trait_ref
), data_id
);
83 let local_data_id
= fx
.cx
.module
.declare_data_in_func(data_id
, &mut fx
.bcx
.func
);
84 fx
.bcx
.ins().global_value(fx
.pointer_type
, local_data_id
)
87 fn build_vtable
<'tcx
>(
88 fx
: &mut FunctionCx
<'_
, 'tcx
, impl Module
>,
89 layout
: TyAndLayout
<'tcx
>,
90 trait_ref
: Option
<ty
::PolyExistentialTraitRef
<'tcx
>>,
93 let usize_size
= fx
.layout_of(fx
.tcx
.types
.usize).size
.bytes() as usize;
95 let drop_in_place_fn
= import_function(
98 Instance
::resolve_drop_in_place(tcx
, layout
.ty
).polymorphize(fx
.tcx
),
101 let mut components
: Vec
<_
> = vec
![Some(drop_in_place_fn
), None
, None
];
104 let methods
= if let Some(trait_ref
) = trait_ref
{
105 methods_root
= tcx
.vtable_methods(trait_ref
.with_self_ty(tcx
, layout
.ty
));
110 let methods
= methods
.cloned().map(|opt_mth
| {
111 opt_mth
.map(|(def_id
, substs
)| {
115 Instance
::resolve_for_vtable(tcx
, ParamEnv
::reveal_all(), def_id
, substs
)
117 .polymorphize(fx
.tcx
),
121 components
.extend(methods
);
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>>()
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
);
133 for (i
, component
) in components
.into_iter().enumerate() {
134 if let Some(func_id
) = component
{
135 let func_ref
= fx
.cx
.module
.declare_func_in_data(func_id
, &mut data_ctx
);
136 data_ctx
.write_function_addr((i
* usize_size
) as u32, func_ref
);
140 data_ctx
.set_align(fx
.tcx
.data_layout
.pointer_align
.pref
.bytes());
147 "__vtable.{}.for.{:?}.{}",
150 .map(|trait_ref
| format
!("{:?}", trait_ref
.skip_binder()).into())
151 .unwrap_or(std
::borrow
::Cow
::Borrowed("???")),
161 // FIXME don't duplicate definitions in lazy jit mode
162 let _
= fx
.cx
.module
.define_data(data_id
, &data_ctx
);
167 fn write_usize(tcx
: TyCtxt
<'_
>, buf
: &mut [u8], idx
: usize, num
: u64) {
168 let pointer_size
= tcx
169 .layout_of(ParamEnv
::reveal_all().and(tcx
.types
.usize))
173 let target
= &mut buf
[idx
* pointer_size
..(idx
+ 1) * pointer_size
];
175 match tcx
.data_layout
.endian
{
176 rustc_target
::abi
::Endian
::Little
=> match pointer_size
{
177 4 => target
.copy_from_slice(&(num
as u32).to_le_bytes()),
178 8 => target
.copy_from_slice(&(num
as u64).to_le_bytes()),
179 _
=> todo
!("pointer size {} is not yet supported", pointer_size
),
181 rustc_target
::abi
::Endian
::Big
=> match pointer_size
{
182 4 => target
.copy_from_slice(&(num
as u32).to_be_bytes()),
183 8 => target
.copy_from_slice(&(num
as u64).to_be_bytes()),
184 _
=> todo
!("pointer size {} is not yet supported", pointer_size
),