2016-09-23 03:27:14 -05:00
|
|
|
use error::EvalResult;
|
2016-10-14 04:31:45 -05:00
|
|
|
use memory::{Memory, Pointer};
|
2016-10-20 05:42:19 -05:00
|
|
|
use primval::{PrimVal, PrimValKind};
|
2016-09-23 03:27:14 -05:00
|
|
|
|
|
|
|
/// A `Value` represents a single self-contained Rust value.
|
|
|
|
///
|
|
|
|
/// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve
|
|
|
|
/// value held directly, outside of any allocation (`ByVal`).
|
|
|
|
///
|
|
|
|
/// For optimization of a few very common cases, there is also a representation for a pair of
|
|
|
|
/// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary
|
|
|
|
/// operations and fat pointers. This idea was taken from rustc's trans.
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
2016-10-14 04:31:45 -05:00
|
|
|
pub enum Value {
|
2016-09-23 03:27:14 -05:00
|
|
|
ByRef(Pointer),
|
|
|
|
ByVal(PrimVal),
|
2016-09-26 10:49:30 -05:00
|
|
|
ByValPair(PrimVal, PrimVal),
|
2016-09-23 03:27:14 -05:00
|
|
|
}
|
|
|
|
|
2016-10-14 04:31:45 -05:00
|
|
|
impl<'a, 'tcx: 'a> Value {
|
|
|
|
pub(super) fn read_ptr(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
|
2016-09-23 03:27:14 -05:00
|
|
|
use self::Value::*;
|
|
|
|
match *self {
|
|
|
|
ByRef(ptr) => mem.read_ptr(ptr),
|
2016-10-20 05:42:19 -05:00
|
|
|
|
|
|
|
ByVal(PrimVal { kind: PrimValKind::Ptr(alloc), bits: offset }) |
|
|
|
|
ByVal(PrimVal { kind: PrimValKind::FnPtr(alloc), bits: offset }) => {
|
|
|
|
let ptr = Pointer::new(alloc, offset as usize);
|
|
|
|
Ok(ptr)
|
|
|
|
}
|
|
|
|
|
2016-09-26 10:49:30 -05:00
|
|
|
ByValPair(..) => unimplemented!(),
|
|
|
|
ByVal(_other) => unimplemented!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-16 03:12:26 -05:00
|
|
|
pub(super) fn expect_ptr_vtable_pair(
|
|
|
|
&self,
|
|
|
|
mem: &Memory<'a, 'tcx>
|
|
|
|
) -> EvalResult<'tcx, (Pointer, Pointer)> {
|
2016-09-23 03:27:14 -05:00
|
|
|
use self::Value::*;
|
|
|
|
match *self {
|
2016-10-16 03:12:26 -05:00
|
|
|
ByRef(ptr) => {
|
|
|
|
let ptr = mem.read_ptr(ptr)?;
|
|
|
|
let vtable = mem.read_ptr(ptr.offset(mem.pointer_size() as isize))?;
|
|
|
|
Ok((ptr, vtable))
|
|
|
|
}
|
2016-10-20 05:42:19 -05:00
|
|
|
|
|
|
|
ByValPair(
|
|
|
|
PrimVal { kind: PrimValKind::Ptr(ptr_alloc), bits: ptr_offset },
|
|
|
|
PrimVal { kind: PrimValKind::Ptr(vtable_alloc), bits: vtable_offset },
|
|
|
|
) => {
|
|
|
|
let ptr = Pointer::new(ptr_alloc, ptr_offset as usize);
|
|
|
|
let vtable = Pointer::new(vtable_alloc, vtable_offset as usize);
|
|
|
|
Ok((ptr, vtable))
|
|
|
|
}
|
|
|
|
|
2016-10-16 03:12:26 -05:00
|
|
|
_ => bug!("expected ptr and vtable, got {:?}", self),
|
2016-09-23 03:27:14 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 04:31:45 -05:00
|
|
|
pub(super) fn expect_slice_len(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, u64> {
|
2016-09-23 03:27:14 -05:00
|
|
|
use self::Value::*;
|
|
|
|
match *self {
|
|
|
|
ByRef(ptr) => mem.read_usize(ptr.offset(mem.pointer_size() as isize)),
|
2016-10-20 05:42:19 -05:00
|
|
|
ByValPair(_, val) if val.kind.is_int() => Ok(val.bits),
|
2016-09-23 03:27:14 -05:00
|
|
|
_ => unimplemented!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|