Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use ty::layout::Size and ty::layout::TargetDataLayout #34

Merged
merged 6 commits into from
Jun 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 11 additions & 15 deletions src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub struct EvalContext<'a, 'tcx: 'a> {
mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,

/// The virtual memory system.
memory: Memory<'tcx>,
memory: Memory<'a, 'tcx>,

/// Precomputed statics, constants and promoteds.
statics: HashMap<ConstantId<'tcx>, Pointer>,
Expand Down Expand Up @@ -138,11 +138,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
tcx: tcx,
mir_map: mir_map,
mir_cache: RefCell::new(DefIdMap()),
memory: Memory::new(tcx.sess
.target
.uint_type
.bit_width()
.expect("Session::target::uint_type was usize")/8),
memory: Memory::new(&tcx.data_layout),
statics: HashMap::new(),
stack: Vec::new(),
}
Expand All @@ -162,7 +158,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
&self.memory
}

pub fn memory_mut(&mut self) -> &mut Memory<'tcx> {
pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx> {
&mut self.memory
}

Expand All @@ -182,7 +178,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ok(ptr)
}
Str(ref s) => {
let psize = self.memory.pointer_size;
let psize = self.memory.pointer_size();
let static_ptr = self.memory.allocate(s.len());
let ptr = self.memory.allocate(psize * 2);
self.memory.write_bytes(static_ptr, s.as_bytes())?;
Expand All @@ -191,7 +187,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ok(ptr)
}
ByteStr(ref bs) => {
let psize = self.memory.pointer_size;
let psize = self.memory.pointer_size();
let static_ptr = self.memory.allocate(bs.len());
let ptr = self.memory.allocate(psize);
self.memory.write_bytes(static_ptr, bs)?;
Expand Down Expand Up @@ -515,7 +511,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
match lv.extra {
LvalueExtra::None => {},
LvalueExtra::Length(len) => {
let len_ptr = dest.offset(self.memory.pointer_size as isize);
let len_ptr = dest.offset(self.memory.pointer_size() as isize);
self.memory.write_usize(len_ptr, len)?;
}
LvalueExtra::DowncastVariant(..) =>
Expand All @@ -541,7 +537,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
(&ty::TyArray(_, length), &ty::TySlice(_)) => {
let len_ptr = dest.offset(self.memory.pointer_size as isize);
let len_ptr = dest.offset(self.memory.pointer_size() as isize);
self.memory.write_usize(len_ptr, length as u64)?;
}

Expand Down Expand Up @@ -655,7 +651,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ok(Size::from_bytes(0))
}
FatPointer { .. } => {
let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size;
let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size();
Ok(Size::from_bytes(bytes as u64))
}
_ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, with layout: {:?}", ty, layout))),
Expand Down Expand Up @@ -766,7 +762,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let ptr = self.memory.read_ptr(base.ptr)?;
let extra = match pointee_ty.sty {
ty::TySlice(_) | ty::TyStr => {
let len_ptr = base.ptr.offset(self.memory.pointer_size as isize);
let len_ptr = base.ptr.offset(self.memory.pointer_size() as isize);
let len = self.memory.read_usize(len_ptr)?;
LvalueExtra::Length(len)
}
Expand Down Expand Up @@ -815,7 +811,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use syntax::ast::{IntTy, UintTy};
let val = match (self.memory.pointer_size, &ty.sty) {
let val = match (self.memory.pointer_size(), &ty.sty) {
(_, &ty::TyBool) => PrimVal::Bool(self.memory.read_bool(ptr)?),
(_, &ty::TyChar) => {
let c = self.memory.read_uint(ptr, 4)? as u32;
Expand Down Expand Up @@ -923,7 +919,7 @@ pub fn eval_main<'a, 'tcx: 'a>(

if mir.arg_decls.len() == 2 {
// start function
let ptr_size = ecx.memory().pointer_size;
let ptr_size = ecx.memory().pointer_size();
let nargs = ecx.memory_mut().allocate(ptr_size);
ecx.memory_mut().write_usize(nargs, 0).unwrap();
let args = ecx.memory_mut().allocate(ptr_size);
Expand Down
6 changes: 3 additions & 3 deletions src/interpreter/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
.collect();
let args_ptrs = args_res?;

let pointer_size = self.memory.pointer_size;
let pointer_size = self.memory.pointer_size();

match name {
"add_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Add, &args[0], &args[1], dest, dest_layout)?,
Expand Down Expand Up @@ -368,7 +368,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
ty::TySlice(_) | ty::TyStr => {
let elem_ty = ty.sequence_element_type(self.tcx);
let elem_size = self.type_size(elem_ty) as u64;
let ptr_size = self.memory.pointer_size as isize;
let ptr_size = self.memory.pointer_size() as isize;
let n = self.memory.read_usize(args_ptrs[0].offset(ptr_size))?;
self.memory.write_uint(dest, n * elem_size, pointer_size)?;
}
Expand Down Expand Up @@ -557,7 +557,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.memory.deallocate(contents_ptr)?;
}
Err(EvalError::ReadBytesAsPointer) => {
let size = self.memory.pointer_size;
let size = self.memory.pointer_size();
let possible_drop_fill = self.memory.read_bytes(ptr, size)?;
if possible_drop_fill.iter().all(|&b| b == mem::POST_DROP_U8) {
return Ok(());
Expand Down
71 changes: 35 additions & 36 deletions src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{fmt, iter, mem, ptr};
use rustc::hir::def_id::DefId;
use rustc::ty::BareFnTy;
use rustc::ty::subst::Substs;
use rustc::ty::layout::TargetDataLayout;

use error::{EvalError, EvalResult};
use primval::PrimVal;
Expand Down Expand Up @@ -53,7 +54,7 @@ pub struct FunctionDefinition<'tcx> {
// Top-level interpreter memory
////////////////////////////////////////////////////////////////////////////////

pub struct Memory<'tcx> {
pub struct Memory<'a, 'tcx> {
/// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations)
alloc_map: HashMap<AllocId, Allocation>,
/// Function "allocations". They exist solely so pointers have something to point to, and
Expand All @@ -62,18 +63,17 @@ pub struct Memory<'tcx> {
/// Inverse map of `functions` so we don't allocate a new pointer every time we need one
function_alloc_cache: HashMap<FunctionDefinition<'tcx>, AllocId>,
next_id: AllocId,
pub pointer_size: usize,
pub layout: &'a TargetDataLayout,
}

impl<'tcx> Memory<'tcx> {
// FIXME: pass tcx.data_layout (This would also allow it to use primitive type alignments to diagnose unaligned memory accesses.)
pub fn new(pointer_size: usize) -> Self {
impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn new(layout: &'a TargetDataLayout) -> Self {
Memory {
alloc_map: HashMap::new(),
functions: HashMap::new(),
function_alloc_cache: HashMap::new(),
next_id: AllocId(0),
pointer_size: pointer_size,
layout: layout,
}
}

Expand Down Expand Up @@ -156,10 +156,13 @@ impl<'tcx> Memory<'tcx> {
Ok(())
}

////////////////////////////////////////////////////////////////////////////////
// Allocation accessors
////////////////////////////////////////////////////////////////////////////////
pub fn pointer_size(&self) -> usize {
self.layout.pointer_size.bytes() as usize
}
}

/// Allocation accessors
impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
match self.alloc_map.get(&id) {
Some(alloc) => Ok(alloc),
Expand Down Expand Up @@ -235,21 +238,20 @@ impl<'tcx> Memory<'tcx> {
if !relocations.is_empty() {
print!("{:1$}", "", prefix.len()); // Print spaces.
let mut pos = 0;
let relocation_width = (self.pointer_size - 1) * 3;
let relocation_width = (self.pointer_size() - 1) * 3;
for (i, target_id) in relocations {
print!("{:1$}", "", (i - pos) * 3);
print!("└{0:─^1$}┘ ", format!("({})", target_id), relocation_width);
pos = i + self.pointer_size;
pos = i + self.pointer_size();
}
println!("");
}
}
}
}

////////////////////////////////////////////////////////////////////////////////
// Byte accessors
////////////////////////////////////////////////////////////////////////////////

/// Byte accessors
impl<'a, 'tcx> Memory<'a, 'tcx> {
fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
let alloc = self.get(ptr.alloc_id)?;
if ptr.offset + size > alloc.bytes.len() {
Expand Down Expand Up @@ -287,11 +289,10 @@ impl<'tcx> Memory<'tcx> {
self.mark_definedness(ptr, size, true)?;
self.get_bytes_unchecked_mut(ptr, size)
}
}

////////////////////////////////////////////////////////////////////////////////
// Reading and writing
////////////////////////////////////////////////////////////////////////////////

/// Reading and writing
impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<'tcx, ()> {
self.check_relocation_edges(src, size)?;

Expand Down Expand Up @@ -336,7 +337,7 @@ impl<'tcx> Memory<'tcx> {
}

pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<'tcx, Pointer> {
let size = self.pointer_size;
let size = self.pointer_size();
self.check_defined(ptr, size)?;
let offset = self.get_bytes_unchecked(ptr, size)?
.read_uint::<NativeEndian>(size).unwrap() as usize;
Expand All @@ -349,7 +350,7 @@ impl<'tcx> Memory<'tcx> {

pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<'tcx, ()> {
{
let size = self.pointer_size;
let size = self.pointer_size();
let mut bytes = self.get_bytes_mut(dest, size)?;
bytes.write_uint::<NativeEndian>(ptr.offset as u64, size).unwrap();
}
Expand All @@ -358,7 +359,7 @@ impl<'tcx> Memory<'tcx> {
}

pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<'tcx, ()> {
let pointer_size = self.pointer_size;
let pointer_size = self.pointer_size();
match val {
PrimVal::Bool(b) => self.write_bool(ptr, b),
PrimVal::I8(n) => self.write_int(ptr, n as i64, 1),
Expand Down Expand Up @@ -406,31 +407,30 @@ impl<'tcx> Memory<'tcx> {
}

pub fn read_isize(&self, ptr: Pointer) -> EvalResult<'tcx, i64> {
self.read_int(ptr, self.pointer_size)
self.read_int(ptr, self.pointer_size())
}

pub fn write_isize(&mut self, ptr: Pointer, n: i64) -> EvalResult<'tcx, ()> {
let size = self.pointer_size;
let size = self.pointer_size();
self.write_int(ptr, n, size)
}

pub fn read_usize(&self, ptr: Pointer) -> EvalResult<'tcx, u64> {
self.read_uint(ptr, self.pointer_size)
self.read_uint(ptr, self.pointer_size())
}

pub fn write_usize(&mut self, ptr: Pointer, n: u64) -> EvalResult<'tcx, ()> {
let size = self.pointer_size;
let size = self.pointer_size();
self.write_uint(ptr, n, size)
}
}

////////////////////////////////////////////////////////////////////////////////
// Relocations
////////////////////////////////////////////////////////////////////////////////

/// Relocations
impl<'a, 'tcx> Memory<'a, 'tcx> {
fn relocations(&self, ptr: Pointer, size: usize)
-> EvalResult<'tcx, btree_map::Range<usize, AllocId>>
{
let start = ptr.offset.saturating_sub(self.pointer_size - 1);
let start = ptr.offset.saturating_sub(self.pointer_size() - 1);
let end = ptr.offset + size;
Ok(self.get(ptr.alloc_id)?.relocations.range(Included(&start), Excluded(&end)))
}
Expand All @@ -444,7 +444,7 @@ impl<'tcx> Memory<'tcx> {
let start = ptr.offset;
let end = start + size;
let first = *keys.first().unwrap();
let last = *keys.last().unwrap() + self.pointer_size;
let last = *keys.last().unwrap() + self.pointer_size();

let alloc = self.get_mut(ptr.alloc_id)?;

Expand Down Expand Up @@ -478,11 +478,10 @@ impl<'tcx> Memory<'tcx> {
self.get_mut(dest.alloc_id)?.relocations.extend(relocations);
Ok(())
}
}

////////////////////////////////////////////////////////////////////////////////
// Undefined bytes
////////////////////////////////////////////////////////////////////////////////

/// Undefined bytes
impl<'a, 'tcx> Memory<'a, 'tcx> {
// FIXME(solson): This is a very naive, slow version.
fn copy_undef_mask(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<'tcx, ()> {
// The bits have to be saved locally before writing to dest in case src and dest overlap.
Expand Down
14 changes: 14 additions & 0 deletions tests/compile-fail/invalid_enum_discriminant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#[repr(C)]
pub enum Foo {
A, B, C, D
}

fn main() {
let f = unsafe { std::mem::transmute::<i32, Foo>(42) };
match f {
Foo::A => {}, //~ ERROR invalid enum discriminant value read
Foo::B => {},
Foo::C => {},
Foo::D => {},
}
}
8 changes: 8 additions & 0 deletions tests/compile-fail/match_char.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fn main() {
assert!(std::char::from_u32(-1_i32 as u32).is_none());
match unsafe { std::mem::transmute::<i32, char>(-1) } {
'a' => {}, //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295
'b' => {},
_ => {},
}
}
2 changes: 1 addition & 1 deletion tests/compiletest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ fn compile_test() {
match cmd.output() {
Ok(ref output) if output.status.success() => writeln!(stderr.lock(), "ok").unwrap(),
Ok(output) => {
writeln!(stderr.lock(), "FAILED with exit code {}", output.status.code().unwrap_or(0)).unwrap();
writeln!(stderr.lock(), "FAILED with exit code {:?}", output.status.code()).unwrap();
writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
writeln!(stderr.lock(), "stderr: \n {}", std::str::from_utf8(&output.stderr).unwrap()).unwrap();
panic!("some tests failed");
Expand Down