]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/value.rs
fe109dbbd63a7e25d2844e303e83f90bd7862268
[rust.git] / src / librustc_mir / interpret / value.rs
1 #![allow(unknown_lints)]
2 #![allow(float_cmp)]
3
4 use rustc::ty::layout::HasDataLayout;
5
6 use super::{
7     EvalError, EvalResult,
8     Memory, MemoryPointer, HasMemory, PointerArithmetic,
9     Machine,
10 };
11
12 pub(super) fn bytes_to_f32(bytes: u128) -> f32 {
13     f32::from_bits(bytes as u32)
14 }
15
16 pub(super) fn bytes_to_f64(bytes: u128) -> f64 {
17     f64::from_bits(bytes as u64)
18 }
19
20 pub(super) fn f32_to_bytes(f: f32) -> u128 {
21     f.to_bits() as u128
22 }
23
24 pub(super) fn f64_to_bytes(f: f64) -> u128 {
25     f.to_bits() as u128
26 }
27
28 /// A `Value` represents a single self-contained Rust value.
29 ///
30 /// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve
31 /// value held directly, outside of any allocation (`ByVal`).  For `ByRef`-values, we remember
32 /// whether the pointer is supposed to be aligned or not (also see Lvalue).
33 ///
34 /// For optimization of a few very common cases, there is also a representation for a pair of
35 /// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary
36 /// operations and fat pointers. This idea was taken from rustc's trans.
37 #[derive(Clone, Copy, Debug)]
38 pub enum Value {
39     ByRef { ptr: Pointer, aligned: bool},
40     ByVal(PrimVal),
41     ByValPair(PrimVal, PrimVal),
42 }
43
44 /// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally.
45 /// This type clears up a few APIs where having a `PrimVal` argument for something that is
46 /// potentially an integer pointer or a pointer to an allocation was unclear.
47 ///
48 /// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just
49 /// the representation of pointers. Also all the sites that convert between primvals and pointers
50 /// are explicit now (and rare!)
51 #[derive(Clone, Copy, Debug)]
52 pub struct Pointer {
53     primval: PrimVal,
54 }
55
56 impl<'tcx> Pointer {
57     pub fn null() -> Self {
58         PrimVal::Bytes(0).into()
59     }
60     pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
61         self.primval.to_ptr()
62     }
63     pub fn into_inner_primval(self) -> PrimVal {
64         self.primval
65     }
66
67     pub(crate) fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
68         let layout = cx.data_layout();
69         match self.primval {
70             PrimVal::Bytes(b) => {
71                 assert_eq!(b as u64 as u128, b);
72                 Ok(Pointer::from(PrimVal::Bytes(layout.signed_offset(b as u64, i)? as u128)))
73             },
74             PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(Pointer::from),
75             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
76         }
77     }
78
79     pub fn offset<C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> {
80         let layout = cx.data_layout();
81         match self.primval {
82             PrimVal::Bytes(b) => {
83                 assert_eq!(b as u64 as u128, b);
84                 Ok(Pointer::from(PrimVal::Bytes(layout.offset(b as u64, i)? as u128)))
85             },
86             PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from),
87             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
88         }
89     }
90
91     pub(crate) fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
92         let layout = cx.data_layout();
93         match self.primval {
94             PrimVal::Bytes(b) => {
95                 assert_eq!(b as u64 as u128, b);
96                 Ok(Pointer::from(PrimVal::Bytes(layout.wrapping_signed_offset(b as u64, i) as u128)))
97             },
98             PrimVal::Ptr(ptr) => Ok(Pointer::from(ptr.wrapping_signed_offset(i, layout))),
99             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
100         }
101     }
102
103     pub fn is_null(self) -> EvalResult<'tcx, bool> {
104         match self.primval {
105             PrimVal::Bytes(b) => Ok(b == 0),
106             PrimVal::Ptr(_) => Ok(false),
107             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
108         }
109     }
110
111     pub fn to_value_with_len(self, len: u64) -> Value {
112         Value::ByValPair(self.primval, PrimVal::from_u128(len as u128))
113     }
114
115     pub fn to_value_with_vtable(self, vtable: MemoryPointer) -> Value {
116         Value::ByValPair(self.primval, PrimVal::Ptr(vtable))
117     }
118
119     pub fn to_value(self) -> Value {
120         Value::ByVal(self.primval)
121     }
122 }
123
124 impl ::std::convert::From<PrimVal> for Pointer {
125     fn from(primval: PrimVal) -> Self {
126         Pointer { primval }
127     }
128 }
129
130 impl ::std::convert::From<MemoryPointer> for Pointer {
131     fn from(ptr: MemoryPointer) -> Self {
132         PrimVal::Ptr(ptr).into()
133     }
134 }
135
136 /// A `PrimVal` represents an immediate, primitive value existing outside of a
137 /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
138 /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes
139 /// of a simple value, a pointer into another `Allocation`, or be undefined.
140 #[derive(Clone, Copy, Debug)]
141 pub enum PrimVal {
142     /// The raw bytes of a simple value.
143     Bytes(u128),
144
145     /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
146     /// relocations, but a `PrimVal` is only large enough to contain one, so we just represent the
147     /// relocation and its associated offset together as a `MemoryPointer` here.
148     Ptr(MemoryPointer),
149
150     /// An undefined `PrimVal`, for representing values that aren't safe to examine, but are safe
151     /// to copy around, just like undefined bytes in an `Allocation`.
152     Undef,
153 }
154
155 #[derive(Clone, Copy, Debug, PartialEq)]
156 pub enum PrimValKind {
157     I8, I16, I32, I64, I128,
158     U8, U16, U32, U64, U128,
159     F32, F64,
160     Bool,
161     Char,
162     Ptr,
163     FnPtr,
164 }
165
166 impl<'a, 'tcx: 'a> Value {
167     #[inline]
168     pub(super) fn by_ref(ptr: Pointer) -> Self {
169         Value::ByRef { ptr, aligned: true }
170     }
171
172     /// Convert the value into a pointer (or a pointer-sized integer).  If the value is a ByRef,
173     /// this may have to perform a load.
174     pub fn into_ptr<M: Machine<'tcx>>(&self, mem: &Memory<'a, 'tcx, M>) -> EvalResult<'tcx, Pointer> {
175         use self::Value::*;
176         match *self {
177             ByRef { ptr, aligned } => {
178                 mem.read_maybe_aligned(aligned, |mem| mem.read_ptr(ptr.to_ptr()?) )
179             },
180             ByVal(ptr) | ByValPair(ptr, _) => Ok(ptr.into()),
181         }
182     }
183
184     pub(super) fn into_ptr_vtable_pair<M: Machine<'tcx>>(
185         &self,
186         mem: &Memory<'a, 'tcx, M>
187     ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> {
188         use self::Value::*;
189         match *self {
190             ByRef { ptr: ref_ptr, aligned } => {
191                 mem.read_maybe_aligned(aligned, |mem| {
192                     let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?;
193                     let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?;
194                     Ok((ptr, vtable.to_ptr()?))
195                 })
196             }
197
198             ByValPair(ptr, vtable) => Ok((ptr.into(), vtable.to_ptr()?)),
199
200             _ => bug!("expected ptr and vtable, got {:?}", self),
201         }
202     }
203
204     pub(super) fn into_slice<M: Machine<'tcx>>(&self, mem: &Memory<'a, 'tcx, M>) -> EvalResult<'tcx, (Pointer, u64)> {
205         use self::Value::*;
206         match *self {
207             ByRef { ptr: ref_ptr, aligned } => {
208                 mem.read_maybe_aligned(aligned, |mem| {
209                     let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?;
210                     let len = mem.read_usize(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?;
211                     Ok((ptr, len))
212                 })
213             },
214             ByValPair(ptr, val) => {
215                 let len = val.to_u128()?;
216                 assert_eq!(len as u64 as u128, len);
217                 Ok((ptr.into(), len as u64))
218             },
219             ByVal(_) => bug!("expected ptr and length, got {:?}", self),
220         }
221     }
222 }
223
224 impl<'tcx> PrimVal {
225     pub fn from_u128(n: u128) -> Self {
226         PrimVal::Bytes(n)
227     }
228
229     pub fn from_i128(n: i128) -> Self {
230         PrimVal::Bytes(n as u128)
231     }
232
233     pub fn from_f32(f: f32) -> Self {
234         PrimVal::Bytes(f32_to_bytes(f))
235     }
236
237     pub fn from_f64(f: f64) -> Self {
238         PrimVal::Bytes(f64_to_bytes(f))
239     }
240
241     pub fn from_bool(b: bool) -> Self {
242         PrimVal::Bytes(b as u128)
243     }
244
245     pub fn from_char(c: char) -> Self {
246         PrimVal::Bytes(c as u128)
247     }
248
249     pub fn to_bytes(self) -> EvalResult<'tcx, u128> {
250         match self {
251             PrimVal::Bytes(b) => Ok(b),
252             PrimVal::Ptr(_) => Err(EvalError::ReadPointerAsBytes),
253             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
254         }
255     }
256
257     pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
258         match self {
259             PrimVal::Bytes(_) => Err(EvalError::ReadBytesAsPointer),
260             PrimVal::Ptr(p) => Ok(p),
261             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
262         }
263     }
264
265     pub fn is_bytes(self) -> bool {
266         match self {
267             PrimVal::Bytes(_) => true,
268             _ => false,
269         }
270     }
271
272     pub fn is_ptr(self) -> bool {
273         match self {
274             PrimVal::Ptr(_) => true,
275             _ => false,
276         }
277     }
278
279     pub fn is_undef(self) -> bool {
280         match self {
281             PrimVal::Undef => true,
282             _ => false,
283         }
284     }
285
286     pub fn to_u128(self) -> EvalResult<'tcx, u128> {
287         self.to_bytes()
288     }
289
290     pub fn to_u64(self) -> EvalResult<'tcx, u64> {
291         self.to_bytes().map(|b| {
292             assert_eq!(b as u64 as u128, b);
293             b as u64
294         })
295     }
296
297     pub fn to_i32(self) -> EvalResult<'tcx, i32> {
298         self.to_bytes().map(|b| {
299             assert_eq!(b as i32 as u128, b);
300             b as i32
301         })
302     }
303
304     pub fn to_i128(self) -> EvalResult<'tcx, i128> {
305         self.to_bytes().map(|b| b as i128)
306     }
307
308     pub fn to_i64(self) -> EvalResult<'tcx, i64> {
309         self.to_bytes().map(|b| {
310             assert_eq!(b as i64 as u128, b);
311             b as i64
312         })
313     }
314
315     pub fn to_f32(self) -> EvalResult<'tcx, f32> {
316         self.to_bytes().map(bytes_to_f32)
317     }
318
319     pub fn to_f64(self) -> EvalResult<'tcx, f64> {
320         self.to_bytes().map(bytes_to_f64)
321     }
322
323     pub fn to_bool(self) -> EvalResult<'tcx, bool> {
324         match self.to_bytes()? {
325             0 => Ok(false),
326             1 => Ok(true),
327             _ => Err(EvalError::InvalidBool),
328         }
329     }
330 }
331
332 impl PrimValKind {
333     pub fn is_int(self) -> bool {
334         use self::PrimValKind::*;
335         match self {
336             I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => true,
337             _ => false,
338         }
339     }
340
341     pub fn is_signed_int(self) -> bool {
342         use self::PrimValKind::*;
343         match self {
344             I8 | I16 | I32 | I64 | I128 => true,
345             _ => false,
346         }
347     }
348
349      pub fn is_float(self) -> bool {
350         use self::PrimValKind::*;
351         match self {
352             F32 | F64 => true,
353             _ => false,
354         }
355     }
356
357     pub fn from_uint_size(size: u64) -> Self {
358         match size {
359             1 => PrimValKind::U8,
360             2 => PrimValKind::U16,
361             4 => PrimValKind::U32,
362             8 => PrimValKind::U64,
363             16 => PrimValKind::U128,
364             _ => bug!("can't make uint with size {}", size),
365         }
366     }
367
368     pub fn from_int_size(size: u64) -> Self {
369         match size {
370             1 => PrimValKind::I8,
371             2 => PrimValKind::I16,
372             4 => PrimValKind::I32,
373             8 => PrimValKind::I64,
374             16 => PrimValKind::I128,
375             _ => bug!("can't make int with size {}", size),
376         }
377     }
378
379     pub fn is_ptr(self) -> bool {
380         use self::PrimValKind::*;
381         match self {
382             Ptr | FnPtr => true,
383             _ => false,
384         }
385     }
386 }