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