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