]> git.lizzy.rs Git - rust.git/blob - src/constant.rs
Print message when reaching trap
[rust.git] / src / constant.rs
1 use std::borrow::Cow;
2
3 use rustc::mir::interpret::{
4     read_target_uint, AllocId, AllocKind, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
5 };
6 use rustc::ty::Const;
7 use rustc_mir::interpret::{
8     InterpretCx, ImmTy, MPlaceTy, Machine, Memory, MemoryKind, OpTy, PlaceTy, Pointer,
9     StackPopCleanup,
10 };
11
12 use cranelift_module::*;
13
14 use crate::prelude::*;
15
16 #[derive(Default)]
17 pub struct ConstantCx {
18     todo: HashSet<TodoItem>,
19     done: HashSet<DataId>,
20 }
21
22 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
23 enum TodoItem {
24     Alloc(AllocId),
25     Static(DefId),
26 }
27
28 impl ConstantCx {
29     pub fn finalize<'a, 'tcx: 'a, B: Backend>(
30         mut self,
31         tcx: TyCtxt<'a, 'tcx, 'tcx>,
32         module: &mut Module<B>,
33     ) {
34         //println!("todo {:?}", self.todo);
35         define_all_allocs(tcx, module, &mut self);
36         //println!("done {:?}", self.done);
37         self.done.clear();
38     }
39 }
40
41 pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
42     ccx.todo.insert(TodoItem::Static(def_id));
43 }
44
45 pub fn codegen_static_ref<'a, 'tcx: 'a>(
46     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
47     def_id: DefId,
48     ty: Ty<'tcx>,
49 ) -> CPlace<'tcx> {
50     let linkage = crate::linkage::get_static_ref_linkage(fx.tcx, def_id);
51     let data_id = data_id_for_static(fx.tcx, fx.module, def_id, linkage);
52     cplace_for_dataid(fx, ty, data_id)
53 }
54
55 pub fn trans_promoted<'a, 'tcx: 'a>(
56     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
57     promoted: Promoted,
58     dest_ty: Ty<'tcx>,
59 ) -> CPlace<'tcx> {
60     match fx
61         .tcx
62         .const_eval(ParamEnv::reveal_all().and(GlobalId {
63             instance: fx.instance,
64             promoted: Some(promoted),
65         }))
66     {
67         Ok(const_) => {
68             let cplace = trans_const_place(fx, const_);
69             debug_assert_eq!(cplace.layout(), fx.layout_of(dest_ty));
70             cplace
71         }
72         Err(_) => {
73             crate::trap::trap_unreachable_ret_place(
74                 fx,
75                 fx.layout_of(dest_ty),
76                 "[panic] Tried to get value of promoted value with errored during const eval.",
77             )
78         }
79     }
80 }
81
82 pub fn trans_constant<'a, 'tcx: 'a>(
83     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
84     constant: &Constant<'tcx>,
85 ) -> CValue<'tcx> {
86     let const_ = force_eval_const(fx, &constant.literal);
87     trans_const_value(fx, const_)
88 }
89
90 pub fn force_eval_const<'a, 'tcx: 'a>(
91     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
92     const_: &'tcx Const,
93 ) -> Const<'tcx> {
94     match const_.val {
95         ConstValue::Unevaluated(def_id, ref substs) => {
96             let param_env = ParamEnv::reveal_all();
97             let substs = fx.monomorphize(substs);
98             let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
99             let cid = GlobalId {
100                 instance,
101                 promoted: None,
102             };
103             fx.tcx.const_eval(param_env.and(cid)).unwrap()
104         }
105         _ => *fx.monomorphize(&const_),
106     }
107 }
108
109 fn trans_const_value<'a, 'tcx: 'a>(
110     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
111     const_: Const<'tcx>,
112 ) -> CValue<'tcx> {
113     let ty = fx.monomorphize(&const_.ty);
114     let layout = fx.layout_of(ty);
115     match ty.sty {
116         ty::Bool => {
117             let bits = const_.val.try_to_bits(layout.size).unwrap();
118             CValue::const_val(fx, ty, bits as u64 as i64)
119         }
120         ty::Uint(_) => {
121             let bits = const_.val.try_to_bits(layout.size).unwrap();
122             CValue::const_val(fx, ty, bits as u64 as i64)
123         }
124         ty::Int(_) => {
125             let bits = const_.val.try_to_bits(layout.size).unwrap();
126             CValue::const_val(fx, ty, rustc::mir::interpret::sign_extend(bits, layout.size) as i128 as i64)
127         }
128         ty::FnDef(_def_id, _substs) => CValue::ByRef(
129             fx.bcx
130                 .ins()
131                 .iconst(fx.pointer_type, fx.pointer_type.bytes() as i64),
132             layout,
133         ),
134         _ => trans_const_place(fx, const_).to_cvalue(fx),
135     }
136 }
137
138 fn trans_const_place<'a, 'tcx: 'a>(
139     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
140     const_: Const<'tcx>,
141 ) -> CPlace<'tcx> {
142     // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
143     let result = || -> EvalResult<'tcx, &'tcx Allocation> {
144         let mut ecx = InterpretCx::new(
145             fx.tcx.at(DUMMY_SP),
146             ty::ParamEnv::reveal_all(),
147             TransPlaceInterpreter,
148         );
149         ecx.push_stack_frame(
150             fx.instance,
151             DUMMY_SP,
152             fx.mir,
153             None,
154             StackPopCleanup::None { cleanup: false },
155         )
156         .unwrap();
157         let op = ecx.eval_operand(
158             &Operand::Constant(Box::new(Constant {
159                 span: DUMMY_SP,
160                 ty: const_.ty,
161                 user_ty: None,
162                 literal: fx.tcx.mk_const(const_),
163             })),
164             None,
165         )?;
166         let ptr = ecx.allocate(op.layout, MemoryKind::Stack);
167         ecx.copy_op(op, ptr.into())?;
168         let alloc = ecx.memory().get(ptr.to_ptr()?.alloc_id)?;
169         Ok(fx.tcx.intern_const_alloc(alloc.clone()))
170     };
171     let alloc = result().expect("unable to convert ConstValue to Allocation");
172
173     //println!("const value: {:?} allocation: {:?}", value, alloc);
174     let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
175     fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
176     let data_id = data_id_for_alloc_id(fx.module, alloc_id);
177     cplace_for_dataid(fx, const_.ty, data_id)
178 }
179
180 fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
181     module
182         .declare_data(&format!("__alloc_{}", alloc_id.0), Linkage::Local, false)
183         .unwrap()
184 }
185
186 fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
187     tcx: TyCtxt<'a, 'tcx, 'tcx>,
188     module: &mut Module<B>,
189     def_id: DefId,
190     linkage: Linkage,
191 ) -> DataId {
192     let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
193     let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
194         true
195     } else {
196         !tcx.type_of(def_id)
197             .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
198     };
199
200     let data_id = module
201         .declare_data(&*symbol_name, linkage, is_mutable)
202         .unwrap();
203
204     if linkage == Linkage::Preemptible {
205         if let ty::RawPtr(_) = tcx.type_of(def_id).sty {
206         } else {
207             tcx.sess.span_fatal(tcx.def_span(def_id), "must have type `*const T` or `*mut T`")
208         }
209
210         let mut data_ctx = DataContext::new();
211         let zero_bytes = std::iter::repeat(0)
212             .take(pointer_ty(tcx).bytes() as usize)
213             .collect::<Vec<u8>>()
214             .into_boxed_slice();
215         data_ctx.define(zero_bytes);
216         match module.define_data(data_id, &data_ctx) {
217             // Everytime a weak static is referenced, there will be a zero pointer definition,
218             // so duplicate definitions are expected and allowed.
219             Err(ModuleError::DuplicateDefinition(_)) => {}
220             res => res.unwrap(),
221         }
222     }
223
224     data_id
225 }
226
227 fn cplace_for_dataid<'a, 'tcx: 'a>(
228     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
229     ty: Ty<'tcx>,
230     data_id: DataId,
231 ) -> CPlace<'tcx> {
232     let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
233     let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
234     let layout = fx.layout_of(fx.monomorphize(&ty));
235     assert!(!layout.is_unsized(), "unsized statics aren't supported");
236     CPlace::Addr(global_ptr, None, layout)
237 }
238
239 fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
240     tcx: TyCtxt<'a, 'tcx, 'tcx>,
241     module: &mut Module<B>,
242     cx: &mut ConstantCx,
243 ) {
244     let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP));
245
246     while let Some(todo_item) = pop_set(&mut cx.todo) {
247         let (data_id, alloc) = match todo_item {
248             TodoItem::Alloc(alloc_id) => {
249                 //println!("alloc_id {}", alloc_id);
250                 let data_id = data_id_for_alloc_id(module, alloc_id);
251                 let alloc = memory.get(alloc_id).unwrap();
252                 (data_id, alloc)
253             }
254             TodoItem::Static(def_id) => {
255                 //println!("static {:?}", def_id);
256
257                 if tcx.is_foreign_item(def_id) {
258                     continue;
259                 }
260
261                 let instance = ty::Instance::mono(tcx, def_id);
262                 let cid = GlobalId {
263                     instance,
264                     promoted: None,
265                 };
266                 let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();
267
268                 let alloc = match const_.val {
269                     ConstValue::ByRef(ptr, alloc) if ptr.offset.bytes() == 0 => alloc,
270                     _ => bug!("static const eval returned {:#?}", const_),
271                 };
272
273                 // FIXME set correct linkage
274                 let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
275                 (data_id, alloc)
276             }
277         };
278
279         //("data_id {}", data_id);
280         if cx.done.contains(&data_id) {
281             continue;
282         }
283
284         let mut data_ctx = DataContext::new();
285
286         data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());
287
288         for &(offset, (_tag, reloc)) in alloc.relocations.iter() {
289             let addend = {
290                 let endianness = tcx.data_layout.endian;
291                 let offset = offset.bytes() as usize;
292                 let ptr_size = tcx.data_layout.pointer_size;
293                 let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
294                 read_target_uint(endianness, bytes).unwrap()
295             };
296
297             let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
298                 AllocKind::Function(instance) => {
299                     assert_eq!(addend, 0);
300                     let func_id = crate::abi::import_function(tcx, module, instance);
301                     let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
302                     data_ctx.write_function_addr(offset.bytes() as u32, local_func_id);
303                     continue;
304                 }
305                 AllocKind::Memory(_) => {
306                     cx.todo.insert(TodoItem::Alloc(reloc));
307                     data_id_for_alloc_id(module, reloc)
308                 }
309                 AllocKind::Static(def_id) => {
310                     cx.todo.insert(TodoItem::Static(def_id));
311                     let linkage = crate::linkage::get_static_ref_linkage(tcx, def_id);
312                     data_id_for_static(tcx, module, def_id, linkage)
313                 }
314             };
315
316             let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
317             data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
318         }
319
320         module.define_data(data_id, &data_ctx).unwrap();
321         cx.done.insert(data_id);
322     }
323
324     assert!(cx.todo.is_empty(), "{:?}", cx.todo);
325 }
326
327 fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
328     if let Some(elem) = set.iter().next().map(|elem| *elem) {
329         set.remove(&elem);
330         Some(elem)
331     } else {
332         None
333     }
334 }
335
336 struct TransPlaceInterpreter;
337
338 impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
339     type MemoryKinds = !;
340     type PointerTag = ();
341     type AllocExtra = ();
342     type MemoryExtra = ();
343     type FrameExtra = ();
344     type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
345     const STATIC_KIND: Option<!> = None;
346
347     fn enforce_validity(_: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool {
348         false
349     }
350
351     fn before_terminator(_: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
352         panic!();
353     }
354
355     fn find_fn(
356         _: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
357         _: Instance<'tcx>,
358         _: &[OpTy<'tcx>],
359         _: Option<PlaceTy<'tcx>>,
360         _: Option<BasicBlock>,
361     ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
362         panic!();
363     }
364
365     fn call_intrinsic(
366         _: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
367         _: Instance<'tcx>,
368         _: &[OpTy<'tcx>],
369         _: PlaceTy<'tcx>,
370     ) -> EvalResult<'tcx> {
371         panic!();
372     }
373
374     fn find_foreign_static(
375         _: DefId,
376         _: ::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
377         _: &(),
378     ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
379         panic!();
380     }
381
382     fn ptr_op(
383         _: &InterpretCx<'a, 'mir, 'tcx, Self>,
384         _: mir::BinOp,
385         _: ImmTy<'tcx>,
386         _: ImmTy<'tcx>,
387     ) -> EvalResult<'tcx, (Scalar, bool)> {
388         panic!();
389     }
390
391     fn box_alloc(_: &mut InterpretCx<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
392         panic!();
393     }
394
395     fn tag_dereference(
396         _: &InterpretCx<'a, 'mir, 'tcx, Self>,
397         _: MPlaceTy<'tcx>,
398         _: Option<::rustc::hir::Mutability>,
399     ) -> EvalResult<'tcx, Scalar> {
400         panic!();
401     }
402
403     fn adjust_static_allocation<'alloc>(
404         alloc: &'alloc Allocation,
405         _: &(),
406     ) -> Cow<'alloc, Allocation> {
407         Cow::Borrowed(alloc)
408     }
409
410     fn tag_new_allocation(
411         _: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
412         ptr: Pointer,
413         _: MemoryKind<!>,
414     ) -> Pointer {
415         ptr
416     }
417
418     fn stack_push(_: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
419         Ok(())
420     }
421
422     fn stack_pop(_: &mut InterpretCx<'a, 'mir, 'tcx, Self>, _: ()) -> EvalResult<'tcx> {
423         Ok(())
424     }
425 }