]> git.lizzy.rs Git - rust.git/blob - src/vtable.rs
Merge pull request #784 from bjorn3/wip_tls_support
[rust.git] / src / vtable.rs
1 //! See librustc_codegen_llvm/meth.rs for reference
2
3 use crate::prelude::*;
4
5 const DROP_FN_INDEX: usize = 0;
6 const SIZE_INDEX: usize = 1;
7 const ALIGN_INDEX: usize = 2;
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 fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, 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         (DROP_FN_INDEX * usize_size) as i32,
22     )
23 }
24
25 pub fn size_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, 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         (SIZE_INDEX * usize_size) as i32,
32     )
33 }
34
35 pub fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, impl Backend>, 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         (ALIGN_INDEX * usize_size) as i32,
42     )
43 }
44
45 pub fn get_ptr_and_method_ref<'tcx>(
46     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
47     arg: CValue<'tcx>,
48     idx: usize,
49 ) -> (Value, Value) {
50     let (ptr, vtable) = arg.load_scalar_pair(fx);
51     let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
52     let func_ref = fx.bcx.ins().load(
53         pointer_ty(fx.tcx),
54         vtable_memflags(),
55         vtable,
56         ((idx + 3) * usize_size as usize) as i32,
57     );
58     (ptr, func_ref)
59 }
60
61 pub fn get_vtable<'tcx>(
62     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
63     layout: TyLayout<'tcx>,
64     trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
65 ) -> Value {
66     let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
67         *data_id
68     } else {
69         let data_id = build_vtable(fx, layout, trait_ref);
70         fx.vtables.insert((layout.ty, trait_ref), data_id);
71         data_id
72     };
73
74     let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
75     fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
76 }
77
78 fn build_vtable<'tcx>(
79     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
80     layout: TyLayout<'tcx>,
81     trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
82 ) -> DataId {
83     let tcx = fx.tcx;
84     let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
85
86     let drop_in_place_fn =
87         import_function(tcx, fx.module, Instance::resolve_drop_in_place(tcx, layout.ty));
88
89     let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None];
90
91     let methods_root;
92     let methods = if let Some(trait_ref) = trait_ref {
93         methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, layout.ty));
94         methods_root.iter()
95     } else {
96         (&[]).iter()
97     };
98     let methods = methods.cloned().map(|opt_mth| {
99         opt_mth.map_or(None, |(def_id, substs)| {
100             Some(import_function(
101                 tcx,
102                 fx.module,
103                 Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
104             ))
105         })
106     });
107     components.extend(methods);
108
109     let mut data_ctx = DataContext::new();
110     let mut data = ::std::iter::repeat(0u8)
111         .take(components.len() * usize_size)
112         .collect::<Vec<u8>>()
113         .into_boxed_slice();
114
115     write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes());
116     write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes());
117     data_ctx.define(data);
118
119     for (i, component) in components.into_iter().enumerate() {
120         if let Some(func_id) = component {
121             let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
122             data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
123         }
124     }
125
126     let data_id = fx
127         .module
128         .declare_data(
129             &format!("vtable.{:?}.for.{:?}", trait_ref, layout.ty),
130             Linkage::Local,
131             false,
132             false,
133             Some(
134                 fx.tcx
135                     .data_layout
136                     .pointer_align
137                     .pref
138                     .bytes()
139                     .try_into()
140                     .unwrap(),
141             ),
142         )
143         .unwrap();
144
145     match fx.module.define_data(data_id, &data_ctx) {
146         Ok(()) | Err(cranelift_module::ModuleError::DuplicateDefinition(_)) => {}
147         err => err.unwrap(),
148     }
149
150     data_id
151 }
152
153 fn write_usize(tcx: TyCtxt, buf: &mut [u8], idx: usize, num: u64) {
154     use byteorder::{BigEndian, LittleEndian, WriteBytesExt};
155
156     let usize_size = tcx
157         .layout_of(ParamEnv::reveal_all().and(tcx.types.usize))
158         .unwrap()
159         .size
160         .bytes() as usize;
161     let mut target = &mut buf[idx * usize_size..(idx + 1) * usize_size];
162
163     match tcx.data_layout.endian {
164         layout::Endian::Little => target.write_uint::<LittleEndian>(num, usize_size),
165         layout::Endian::Big => target.write_uint::<BigEndian>(num, usize_size),
166     }
167     .unwrap()
168 }