Refactor in preparation for Value
locals.
Turning locals into `Vec<Value>` will allow writing `PrimVal` results directly into the locals array without creating `memory::Allocation`s for every local. This will entail passing around a generalized kind of `Lvalue` instead of `Pointer`s for the destinations of operations. Replacing `Pointer` with `Lvalue` is mostly done with this commit, but expanding `Lvalue` will come later. This commit turns every local from `Pointer` into `Value::ByRef(ptr)`. Locals which are `Value::ByVal(prim_val)` will come in a later commit.
This commit is contained in:
parent
cb23b8d0a7
commit
5f65ee2713
@ -78,7 +78,7 @@ pub struct Frame<'a, 'tcx: 'a> {
|
||||
|
||||
/// The list of locals for the current function, stored in order as
|
||||
/// `[return_ptr, arguments..., variables..., temporaries...]`.
|
||||
pub locals: Vec<Pointer>,
|
||||
pub locals: Vec<Value>,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Current position within the function
|
||||
@ -93,7 +93,7 @@ pub struct Frame<'a, 'tcx: 'a> {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
struct Lvalue {
|
||||
pub struct Lvalue {
|
||||
ptr: Pointer,
|
||||
extra: LvalueExtra,
|
||||
}
|
||||
@ -157,7 +157,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_ret_ptr(&mut self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, Pointer> {
|
||||
pub fn alloc_ptr(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
substs: &'tcx Substs<'tcx>
|
||||
) -> EvalResult<'tcx, Pointer> {
|
||||
let size = self.type_size_with_substs(ty, substs);
|
||||
let align = self.type_align_with_substs(ty, substs);
|
||||
self.memory.allocate(size, align)
|
||||
@ -175,7 +179,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
&self.stack
|
||||
}
|
||||
|
||||
fn target_isize_primval(&self, n: i64) -> PrimVal {
|
||||
fn isize_primval(&self, n: i64) -> PrimVal {
|
||||
match self.memory.pointer_size() {
|
||||
1 => PrimVal::I8(n as i8),
|
||||
2 => PrimVal::I16(n as i16),
|
||||
@ -185,7 +189,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn target_usize_primval(&self, n: u64) -> PrimVal {
|
||||
fn usize_primval(&self, n: u64) -> PrimVal {
|
||||
match self.memory.pointer_size() {
|
||||
1 => PrimVal::U8(n as u8),
|
||||
2 => PrimVal::U16(n as u16),
|
||||
@ -200,7 +204,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let ptr = self.memory.allocate(s.len(), 1)?;
|
||||
self.memory.write_bytes(ptr, s.as_bytes())?;
|
||||
self.memory.freeze(ptr.alloc_id)?;
|
||||
Ok(Value::ByValPair(PrimVal::Ptr(ptr), self.target_usize_primval(s.len() as u64)))
|
||||
Ok(Value::ByValPair(PrimVal::Ptr(ptr), self.usize_primval(s.len() as u64)))
|
||||
}
|
||||
|
||||
fn const_to_value(&mut self, const_val: &ConstVal) -> EvalResult<'tcx, Value> {
|
||||
@ -326,19 +330,24 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
span: codemap::Span,
|
||||
mir: CachedMir<'a, 'tcx>,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
return_ptr: Pointer,
|
||||
return_lvalue: Lvalue,
|
||||
return_to_block: StackPopCleanup,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
let local_tys = mir.local_decls.iter().map(|a| a.ty);
|
||||
|
||||
::log_settings::settings().indentation += 1;
|
||||
|
||||
// FIXME(solson)
|
||||
let return_ptr = return_lvalue.to_ptr();
|
||||
|
||||
// directly change the first allocation (the return value) to *be* the allocation where the
|
||||
// caller stores the result
|
||||
let locals: EvalResult<'tcx, Vec<Pointer>> = iter::once(Ok(return_ptr)).chain(local_tys.skip(1).map(|ty| {
|
||||
let locals: EvalResult<'tcx, Vec<Value>> = iter::once(Ok(Value::ByRef(return_ptr))).chain(local_tys.skip(1).map(|ty| {
|
||||
let size = self.type_size_with_substs(ty, substs);
|
||||
let align = self.type_align_with_substs(ty, substs);
|
||||
self.memory.allocate(size, align)
|
||||
|
||||
// FIXME(solson)
|
||||
self.memory.allocate(size, align).map(Value::ByRef)
|
||||
})).collect();
|
||||
|
||||
self.stack.push(Frame {
|
||||
@ -377,7 +386,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
op: mir::BinOp,
|
||||
left: &mir::Operand<'tcx>,
|
||||
right: &mir::Operand<'tcx>,
|
||||
dest: Pointer,
|
||||
dest: Lvalue,
|
||||
dest_layout: &'tcx Layout,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
use rustc::ty::layout::Layout::*;
|
||||
@ -387,6 +396,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
};
|
||||
|
||||
let overflowed = self.intrinsic_overflowing(op, left, right, dest)?;
|
||||
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
let offset = tup_layout.offsets[1].bytes() as isize;
|
||||
self.memory.write_bool(dest.offset(offset), overflowed)
|
||||
}
|
||||
@ -398,26 +411,29 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
op: mir::BinOp,
|
||||
left: &mir::Operand<'tcx>,
|
||||
right: &mir::Operand<'tcx>,
|
||||
dest: Pointer,
|
||||
dest: Lvalue,
|
||||
) -> EvalResult<'tcx, bool> {
|
||||
let left_primval = self.eval_operand_to_primval(left)?;
|
||||
let right_primval = self.eval_operand_to_primval(right)?;
|
||||
let (val, overflow) = primval::binary_op(op, left_primval, right_primval)?;
|
||||
self.memory.write_primval(dest, val)?;
|
||||
self.write_primval(dest, val)?;
|
||||
Ok(overflow)
|
||||
}
|
||||
|
||||
fn assign_fields<I: IntoIterator<Item = u64>>(
|
||||
&mut self,
|
||||
dest: Pointer,
|
||||
dest: Lvalue,
|
||||
offsets: I,
|
||||
operands: &[mir::Operand<'tcx>],
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
for (offset, operand) in offsets.into_iter().zip(operands) {
|
||||
let value = self.eval_operand(operand)?;
|
||||
let value_ty = self.operand_ty(operand);
|
||||
let field_dest = dest.offset(offset as isize);
|
||||
self.write_value(value, field_dest, value_ty)?;
|
||||
self.write_value_to_ptr(value, field_dest, value_ty)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -431,7 +447,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
rvalue: &mir::Rvalue<'tcx>,
|
||||
lvalue: &mir::Lvalue<'tcx>,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
let dest = self.eval_lvalue(lvalue)?.to_ptr();
|
||||
let dest = self.eval_lvalue(lvalue)?;
|
||||
let dest_ty = self.lvalue_ty(lvalue);
|
||||
let dest_layout = self.type_layout(dest_ty);
|
||||
|
||||
@ -453,7 +469,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
UnaryOp(un_op, ref operand) => {
|
||||
let val = self.eval_operand_to_primval(operand)?;
|
||||
self.memory.write_primval(dest, primval::unary_op(un_op, val)?)?;
|
||||
self.write_primval(dest, primval::unary_op(un_op, val)?)?;
|
||||
}
|
||||
|
||||
Aggregate(ref kind, ref operands) => {
|
||||
@ -478,7 +494,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let discr_val = adt_def.variants[variant].disr_val.to_u64_unchecked();
|
||||
let discr_size = discr.size().bytes() as usize;
|
||||
let discr_offset = variants[variant].offsets[0].bytes() as isize;
|
||||
let discr_dest = dest.offset(discr_offset);
|
||||
|
||||
// FIXME(solson)
|
||||
let discr_dest = (dest.to_ptr()).offset(discr_offset);
|
||||
|
||||
self.memory.write_uint(discr_dest, discr_val, discr_size)?;
|
||||
|
||||
// Don't include the first offset; it's for the discriminant.
|
||||
@ -500,7 +519,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
self.write_value(value, dest, value_ty)?;
|
||||
} else {
|
||||
assert_eq!(operands.len(), 0);
|
||||
self.memory.write_isize(dest, 0)?;
|
||||
let zero = self.isize_primval(0);
|
||||
self.write_primval(dest, zero)?;
|
||||
}
|
||||
} else {
|
||||
bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
|
||||
@ -518,6 +538,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
assert_eq!(self.type_size(operand_ty), 0);
|
||||
}
|
||||
let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield)?;
|
||||
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
let dest = dest.offset(offset.bytes() as isize);
|
||||
try!(self.memory.write_isize(dest, 0));
|
||||
}
|
||||
@ -532,6 +556,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let val = adt_def.variants[variant].disr_val.to_u64_unchecked();
|
||||
let size = discr.size().bytes() as usize;
|
||||
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
if signed {
|
||||
self.memory.write_int(dest, val as i64, size)?;
|
||||
} else {
|
||||
@ -553,9 +580,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
};
|
||||
let elem_size = self.type_size(elem_ty);
|
||||
let value = self.eval_operand(operand)?;
|
||||
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
for i in 0..length {
|
||||
let elem_dest = dest.offset((i * elem_size) as isize);
|
||||
self.write_value(value, elem_dest, elem_ty)?;
|
||||
self.write_value_to_ptr(value, elem_dest, elem_ty)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,10 +594,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let src = self.eval_lvalue(lvalue)?;
|
||||
let ty = self.lvalue_ty(lvalue);
|
||||
let (_, len) = src.elem_ty_and_len(ty);
|
||||
self.memory.write_usize(dest, len)?;
|
||||
let len_val = self.usize_primval(len);
|
||||
self.write_primval(dest, len_val)?;
|
||||
}
|
||||
|
||||
Ref(_, _, ref lvalue) => {
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
let lvalue = self.eval_lvalue(lvalue)?;
|
||||
self.memory.write_ptr(dest, lvalue.ptr)?;
|
||||
let extra_ptr = dest.offset(self.memory.pointer_size() as isize);
|
||||
@ -580,6 +615,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
Box(ty) => {
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
let size = self.type_size(ty);
|
||||
let align = self.type_align(ty);
|
||||
let ptr = self.memory.allocate(size, align)?;
|
||||
@ -587,6 +625,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
Cast(kind, ref operand, cast_ty) => {
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
|
||||
use rustc::mir::repr::CastKind::*;
|
||||
match kind {
|
||||
@ -778,7 +819,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> {
|
||||
use rustc::mir::repr::Lvalue::*;
|
||||
let ptr = match *lvalue {
|
||||
Local(i) => self.frame().locals[i.index()],
|
||||
Local(i) => {
|
||||
match self.frame().locals[i.index()] {
|
||||
Value::ByRef(p) => p,
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
Static(def_id) => {
|
||||
let substs = subst::Substs::empty(self.tcx);
|
||||
@ -910,7 +956,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
self.monomorphize(operand.ty(&self.mir(), self.tcx), self.substs())
|
||||
}
|
||||
|
||||
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
|
||||
fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
|
||||
let size = self.type_size(ty);
|
||||
let align = self.type_align(ty);
|
||||
self.memory.copy(src, dest, size, align)?;
|
||||
@ -957,14 +1003,36 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_primval(
|
||||
&mut self,
|
||||
dest: Lvalue,
|
||||
val: PrimVal,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
self.memory.write_primval(dest, val)
|
||||
}
|
||||
|
||||
fn write_value(
|
||||
&mut self,
|
||||
value: Value,
|
||||
dest: Lvalue,
|
||||
dest_ty: Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
self.write_value_to_ptr(value, dest, dest_ty)
|
||||
}
|
||||
|
||||
fn write_value_to_ptr(
|
||||
&mut self,
|
||||
value: Value,
|
||||
dest: Pointer,
|
||||
dest_ty: Ty<'tcx>
|
||||
dest_ty: Ty<'tcx>,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
match value {
|
||||
Value::ByRef(ptr) => self.move_(ptr, dest, dest_ty),
|
||||
Value::ByRef(ptr) => self.copy(ptr, dest, dest_ty),
|
||||
Value::ByVal(primval) => self.memory.write_primval(dest, primval),
|
||||
Value::ByValPair(a, b) => {
|
||||
self.memory.write_primval(dest, a)?;
|
||||
@ -984,7 +1052,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
|
||||
use syntax::ast::{IntTy, UintTy, FloatTy};
|
||||
use syntax::ast::FloatTy;
|
||||
|
||||
let val = match &ty.sty {
|
||||
&ty::TyBool => PrimVal::Bool(self.memory.read_bool(ptr)?),
|
||||
&ty::TyChar => {
|
||||
@ -995,17 +1064,31 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
&ty::TyInt(IntTy::I8) => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8),
|
||||
&ty::TyInt(IntTy::I16) => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16),
|
||||
&ty::TyInt(IntTy::I32) => PrimVal::I32(self.memory.read_int(ptr, 4)? as i32),
|
||||
&ty::TyInt(IntTy::I64) => PrimVal::I64(self.memory.read_int(ptr, 8)? as i64),
|
||||
&ty::TyUint(UintTy::U8) => PrimVal::U8(self.memory.read_uint(ptr, 1)? as u8),
|
||||
&ty::TyUint(UintTy::U16) => PrimVal::U16(self.memory.read_uint(ptr, 2)? as u16),
|
||||
&ty::TyUint(UintTy::U32) => PrimVal::U32(self.memory.read_uint(ptr, 4)? as u32),
|
||||
&ty::TyUint(UintTy::U64) => PrimVal::U64(self.memory.read_uint(ptr, 8)? as u64),
|
||||
&ty::TyInt(int_ty) => {
|
||||
use syntax::ast::IntTy::*;
|
||||
let size = match int_ty {
|
||||
I8 => 1,
|
||||
I16 => 2,
|
||||
I32 => 4,
|
||||
I64 => 8,
|
||||
Is => self.memory.pointer_size(),
|
||||
};
|
||||
let n = self.memory.read_int(ptr, size)?;
|
||||
PrimVal::int_with_size(n, size)
|
||||
}
|
||||
|
||||
&ty::TyInt(IntTy::Is) => self.target_isize_primval(self.memory.read_isize(ptr)?),
|
||||
&ty::TyUint(UintTy::Us) => self.target_usize_primval(self.memory.read_usize(ptr)?),
|
||||
&ty::TyUint(uint_ty) => {
|
||||
use syntax::ast::UintTy::*;
|
||||
let size = match uint_ty {
|
||||
U8 => 1,
|
||||
U16 => 2,
|
||||
U32 => 4,
|
||||
U64 => 8,
|
||||
Us => self.memory.pointer_size(),
|
||||
};
|
||||
let n = self.memory.read_uint(ptr, size)?;
|
||||
PrimVal::uint_with_size(n, size)
|
||||
}
|
||||
|
||||
&ty::TyFloat(FloatTy::F32) => PrimVal::F32(self.memory.read_f32(ptr)?),
|
||||
&ty::TyFloat(FloatTy::F64) => PrimVal::F64(self.memory.read_f64(ptr)?),
|
||||
@ -1026,7 +1109,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let extra = match self.tcx.struct_tail(ty).sty {
|
||||
ty::TyTrait(..) => PrimVal::Ptr(self.memory.read_ptr(extra)?),
|
||||
ty::TySlice(..) |
|
||||
ty::TyStr => self.target_usize_primval(self.memory.read_usize(extra)?),
|
||||
ty::TyStr => self.usize_primval(self.memory.read_usize(extra)?),
|
||||
_ => bug!("unsized primval ptr read from {:?}", ty),
|
||||
};
|
||||
return Ok(Value::ByValPair(PrimVal::Ptr(p), extra));
|
||||
@ -1036,16 +1119,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
&ty::TyAdt(..) => {
|
||||
use rustc::ty::layout::Layout::*;
|
||||
if let CEnum { discr, signed, .. } = *self.type_layout(ty) {
|
||||
match (discr.size().bytes(), signed) {
|
||||
(1, true) => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8),
|
||||
(2, true) => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16),
|
||||
(4, true) => PrimVal::I32(self.memory.read_int(ptr, 4)? as i32),
|
||||
(8, true) => PrimVal::I64(self.memory.read_int(ptr, 8)? as i64),
|
||||
(1, false) => PrimVal::U8(self.memory.read_uint(ptr, 1)? as u8),
|
||||
(2, false) => PrimVal::U16(self.memory.read_uint(ptr, 2)? as u16),
|
||||
(4, false) => PrimVal::U32(self.memory.read_uint(ptr, 4)? as u32),
|
||||
(8, false) => PrimVal::U64(self.memory.read_uint(ptr, 8)? as u64),
|
||||
(size, _) => bug!("CEnum discr size {}", size),
|
||||
let size = discr.size().bytes() as usize;
|
||||
if signed {
|
||||
let n = self.memory.read_int(ptr, size)?;
|
||||
PrimVal::int_with_size(n, size)
|
||||
} else {
|
||||
let n = self.memory.read_uint(ptr, size)?;
|
||||
PrimVal::uint_with_size(n, size)
|
||||
}
|
||||
} else {
|
||||
bug!("primitive read of non-clike enum: {:?}", ty);
|
||||
@ -1100,7 +1180,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
// For now, upcasts are limited to changes in marker
|
||||
// traits, and hence never actually require an actual
|
||||
// change to the vtable.
|
||||
self.write_value(src, dest, dest_ty)?;
|
||||
self.write_value_to_ptr(src, dest, dest_ty)?;
|
||||
},
|
||||
(_, &ty::TyTrait(ref data)) => {
|
||||
let trait_ref = data.principal.with_self_ty(self.tcx, src_pointee_ty);
|
||||
@ -1146,7 +1226,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let src_f_ptr = src_ptr.offset(src_field_offset);
|
||||
let dst_f_ptr = dest.offset(dst_field_offset);
|
||||
if src_fty == dst_fty {
|
||||
self.move_(src_f_ptr, dst_f_ptr, src_fty)?;
|
||||
self.copy(src_f_ptr, dst_f_ptr, src_fty)?;
|
||||
} else {
|
||||
self.unsize_into(Value::ByRef(src_f_ptr), src_fty, dst_f_ptr, dst_fty)?;
|
||||
}
|
||||
@ -1161,10 +1241,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl Lvalue {
|
||||
fn from_ptr(ptr: Pointer) -> Self {
|
||||
Lvalue { ptr: ptr, extra: LvalueExtra::None }
|
||||
}
|
||||
|
||||
fn to_ptr(self) -> Pointer {
|
||||
assert_eq!(self.extra, LvalueExtra::None);
|
||||
self.ptr
|
||||
}
|
||||
|
||||
fn elem_ty_and_len<'tcx>(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
|
||||
match ty.sty {
|
||||
ty::TyArray(elem, n) => (elem, n as u64),
|
||||
@ -1199,27 +1284,22 @@ pub fn eval_main<'a, 'tcx: 'a>(
|
||||
let mir = mir_map.map.get(&def_id).expect("no mir for main function");
|
||||
let mut ecx = EvalContext::new(tcx, mir_map, memory_size, stack_limit);
|
||||
let substs = subst::Substs::empty(tcx);
|
||||
let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs)
|
||||
let return_ptr = ecx.alloc_ptr(mir.return_ty, substs)
|
||||
.expect("should at least be able to allocate space for the main function's return value");
|
||||
|
||||
ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, return_ptr, StackPopCleanup::None)
|
||||
.expect("could not allocate first stack frame");
|
||||
|
||||
// FIXME: this is a horrible and wrong way to detect the start function, but overwriting the first two locals shouldn't do much
|
||||
if mir.local_decls.len() > 2 {
|
||||
// start function
|
||||
let nargs = ecx.frame_mut().locals[1];
|
||||
let args = ecx.frame_mut().locals[2];
|
||||
// ignore errors, if the locals are too small this is not the start function
|
||||
let _ = ecx.memory_mut().write_usize(nargs, 0);
|
||||
let _ = ecx.memory_mut().write_usize(args, 0);
|
||||
}
|
||||
ecx.push_stack_frame(
|
||||
def_id,
|
||||
mir.span,
|
||||
CachedMir::Ref(mir),
|
||||
substs,
|
||||
Lvalue::from_ptr(return_ptr), // FIXME(solson)
|
||||
StackPopCleanup::None
|
||||
).expect("could not allocate first stack frame");
|
||||
|
||||
for _ in 0..step_limit {
|
||||
match ecx.step() {
|
||||
Ok(true) => {}
|
||||
Ok(false) => return,
|
||||
// FIXME: diverging functions can end up here in some future miri
|
||||
Err(e) => {
|
||||
report(tcx, &ecx, e);
|
||||
return;
|
||||
|
@ -6,6 +6,7 @@ use super::{
|
||||
CachedMir,
|
||||
ConstantId,
|
||||
EvalContext,
|
||||
Lvalue,
|
||||
ConstantKind,
|
||||
StackPopCleanup,
|
||||
};
|
||||
@ -104,7 +105,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
// WARNING: make sure that any methods implemented on this type don't ever access ecx.stack
|
||||
// this includes any method that might access the stack
|
||||
// basically don't call anything other than `load_mir`, `alloc_ret_ptr`, `push_stack_frame`
|
||||
// basically don't call anything other than `load_mir`, `alloc_ptr`, `push_stack_frame`
|
||||
// The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons
|
||||
struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> {
|
||||
span: Span,
|
||||
@ -127,14 +128,15 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
|
||||
}
|
||||
self.try(|this| {
|
||||
let mir = this.ecx.load_mir(def_id)?;
|
||||
let ptr = this.ecx.alloc_ret_ptr(mir.return_ty, substs)?;
|
||||
// FIXME(solson): Don't allocate a pointer unconditionally.
|
||||
let ptr = this.ecx.alloc_ptr(mir.return_ty, substs)?;
|
||||
this.ecx.statics.insert(cid.clone(), ptr);
|
||||
let cleanup = if immutable && !mir.return_ty.type_contents(this.ecx.tcx).interior_unsafe() {
|
||||
StackPopCleanup::Freeze(ptr.alloc_id)
|
||||
} else {
|
||||
StackPopCleanup::None
|
||||
};
|
||||
this.ecx.push_stack_frame(def_id, span, mir, substs, ptr, cleanup)
|
||||
this.ecx.push_stack_frame(def_id, span, mir, substs, Lvalue::from_ptr(ptr), cleanup)
|
||||
});
|
||||
}
|
||||
fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, ()>>(&mut self, f: F) {
|
||||
@ -176,14 +178,15 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
|
||||
let mir = self.mir.promoted[index].clone();
|
||||
let return_ty = mir.return_ty;
|
||||
self.try(|this| {
|
||||
let return_ptr = this.ecx.alloc_ret_ptr(return_ty, cid.substs)?;
|
||||
// FIXME(solson): Don't allocate a pointer unconditionally.
|
||||
let return_ptr = this.ecx.alloc_ptr(return_ty, cid.substs)?;
|
||||
let mir = CachedMir::Owned(Rc::new(mir));
|
||||
this.ecx.statics.insert(cid.clone(), return_ptr);
|
||||
this.ecx.push_stack_frame(this.def_id,
|
||||
constant.span,
|
||||
mir,
|
||||
this.substs,
|
||||
return_ptr,
|
||||
Lvalue::from_ptr(return_ptr),
|
||||
StackPopCleanup::Freeze(return_ptr.alloc_id))
|
||||
});
|
||||
}
|
||||
|
@ -5,10 +5,9 @@ use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, Ty};
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
use memory::Pointer;
|
||||
use interpreter::EvalContext;
|
||||
use primval::{self, PrimVal};
|
||||
use interpreter::value::Value;
|
||||
use interpreter::{EvalContext, Lvalue};
|
||||
use primval::{self, PrimVal};
|
||||
|
||||
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
pub(super) fn call_intrinsic(
|
||||
@ -16,7 +15,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
def_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
dest: Pointer,
|
||||
dest: Lvalue,
|
||||
dest_ty: Ty<'tcx>,
|
||||
dest_layout: &'tcx Layout,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
@ -24,7 +23,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
.map(|arg| self.eval_operand(arg))
|
||||
.collect();
|
||||
let args_ptrs = args_ptrs?;
|
||||
let pointer_size = self.memory.pointer_size();
|
||||
let i32 = self.tcx.types.i32;
|
||||
let isize = self.tcx.types.isize;
|
||||
let usize = self.tcx.types.usize;
|
||||
@ -33,15 +31,41 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
let intrinsic_name = &self.tcx.item_name(def_id).as_str()[..];
|
||||
match intrinsic_name {
|
||||
"add_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Add, &args[0], &args[1], dest, dest_layout)?,
|
||||
"sub_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Sub, &args[0], &args[1], dest, dest_layout)?,
|
||||
"mul_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Mul, &args[0], &args[1], dest, dest_layout)?,
|
||||
"add_with_overflow" => {
|
||||
self.intrinsic_with_overflow(
|
||||
mir::BinOp::Add,
|
||||
&args[0],
|
||||
&args[1],
|
||||
dest,
|
||||
dest_layout,
|
||||
)?
|
||||
}
|
||||
|
||||
"sub_with_overflow" => {
|
||||
self.intrinsic_with_overflow(
|
||||
mir::BinOp::Sub,
|
||||
&args[0],
|
||||
&args[1],
|
||||
dest,
|
||||
dest_layout,
|
||||
)?
|
||||
}
|
||||
|
||||
"mul_with_overflow" => {
|
||||
self.intrinsic_with_overflow(
|
||||
mir::BinOp::Mul,
|
||||
&args[0],
|
||||
&args[1],
|
||||
dest,
|
||||
dest_layout,
|
||||
)?
|
||||
}
|
||||
|
||||
"arith_offset" => {
|
||||
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
|
||||
let offset = self.value_to_primval(args_ptrs[1], isize)?.expect_int("arith_offset second arg not isize");
|
||||
let new_ptr = ptr.offset(offset as isize);
|
||||
self.memory.write_ptr(dest, new_ptr)?;
|
||||
self.write_primval(dest, PrimVal::Ptr(new_ptr))?;
|
||||
}
|
||||
|
||||
"assume" => {
|
||||
@ -72,24 +96,24 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let elem_ty = substs.type_at(0);
|
||||
let num = self.value_to_primval(args_ptrs[0], elem_ty)?;
|
||||
let num = numeric_intrinsic(intrinsic_name, num);
|
||||
self.memory.write_primval(dest, num)?;
|
||||
self.write_primval(dest, num)?;
|
||||
}
|
||||
|
||||
"discriminant_value" => {
|
||||
let ty = substs.type_at(0);
|
||||
let adt_ptr = args_ptrs[0].read_ptr(&self.memory)?;
|
||||
let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
|
||||
self.memory.write_uint(dest, discr_val, 8)?;
|
||||
self.write_primval(dest, PrimVal::U64(discr_val))?;
|
||||
}
|
||||
|
||||
"fabsf32" => {
|
||||
let f = self.value_to_primval(args_ptrs[2], f32)?.expect_f32("fabsf32 read non f32");
|
||||
self.memory.write_f32(dest, f.abs())?;
|
||||
self.write_primval(dest, PrimVal::F32(f.abs()))?;
|
||||
}
|
||||
|
||||
"fabsf64" => {
|
||||
let f = self.value_to_primval(args_ptrs[2], f64)?.expect_f64("fabsf64 read non f64");
|
||||
self.memory.write_f64(dest, f.abs())?;
|
||||
self.write_primval(dest, PrimVal::F64(f.abs()))?;
|
||||
}
|
||||
|
||||
"fadd_fast" => {
|
||||
@ -97,37 +121,47 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let a = self.value_to_primval(args_ptrs[0], ty)?;
|
||||
let b = self.value_to_primval(args_ptrs[0], ty)?;
|
||||
let result = primval::binary_op(mir::BinOp::Add, a, b)?;
|
||||
self.memory.write_primval(dest, result.0)?;
|
||||
self.write_primval(dest, result.0)?;
|
||||
}
|
||||
|
||||
"likely" |
|
||||
"unlikely" |
|
||||
"forget" => {}
|
||||
|
||||
"init" => self.memory.write_repeat(dest, 0, dest_layout.size(&self.tcx.data_layout).bytes() as usize)?,
|
||||
"init" => {
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
let size = dest_layout.size(&self.tcx.data_layout).bytes() as usize;
|
||||
self.memory.write_repeat(dest, 0, size)?;
|
||||
}
|
||||
|
||||
"min_align_of" => {
|
||||
let elem_ty = substs.type_at(0);
|
||||
let elem_align = self.type_align(elem_ty);
|
||||
self.memory.write_uint(dest, elem_align as u64, pointer_size)?;
|
||||
let align_val = self.usize_primval(elem_align as u64);
|
||||
self.write_primval(dest, align_val)?;
|
||||
}
|
||||
|
||||
"pref_align_of" => {
|
||||
let ty = substs.type_at(0);
|
||||
let layout = self.type_layout(ty);
|
||||
let align = layout.align(&self.tcx.data_layout).pref();
|
||||
self.memory.write_uint(dest, align, pointer_size)?;
|
||||
let align_val = self.usize_primval(align);
|
||||
self.write_primval(dest, align_val)?;
|
||||
}
|
||||
|
||||
"move_val_init" => {
|
||||
let ty = substs.type_at(0);
|
||||
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
|
||||
self.write_value(args_ptrs[1], ptr, ty)?;
|
||||
self.write_value_to_ptr(args_ptrs[1], ptr, ty)?;
|
||||
}
|
||||
|
||||
"needs_drop" => {
|
||||
let ty = substs.type_at(0);
|
||||
self.memory.write_bool(dest, self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment()))?;
|
||||
let env = self.tcx.empty_parameter_environment();
|
||||
let needs_drop = self.tcx.type_needs_drop_given_env(ty, &env);
|
||||
self.write_primval(dest, PrimVal::Bool(needs_drop))?;
|
||||
}
|
||||
|
||||
"offset" => {
|
||||
@ -137,7 +171,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
|
||||
let result_ptr = ptr.offset(offset as isize * pointee_size);
|
||||
self.memory.write_ptr(dest, result_ptr)?;
|
||||
self.write_primval(dest, PrimVal::Ptr(result_ptr))?;
|
||||
}
|
||||
|
||||
"overflowing_sub" => {
|
||||
@ -155,35 +189,37 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
"powif32" => {
|
||||
let f = self.value_to_primval(args_ptrs[0], f32)?.expect_f32("powif32 first arg not f32");
|
||||
let i = self.value_to_primval(args_ptrs[1], i32)?.expect_int("powif32 second arg not i32");
|
||||
self.memory.write_f32(dest, f.powi(i as i32))?;
|
||||
self.write_primval(dest, PrimVal::F32(f.powi(i as i32)))?;
|
||||
}
|
||||
|
||||
"powif64" => {
|
||||
let f = self.value_to_primval(args_ptrs[0], f64)?.expect_f64("powif64 first arg not f64");
|
||||
let i = self.value_to_primval(args_ptrs[1], i32)?.expect_int("powif64 second arg not i32");
|
||||
self.memory.write_f64(dest, f.powi(i as i32))?;
|
||||
self.write_primval(dest, PrimVal::F64(f.powi(i as i32)))?;
|
||||
}
|
||||
|
||||
"sqrtf32" => {
|
||||
let f = self.value_to_primval(args_ptrs[0], f32)?.expect_f32("sqrtf32 first arg not f32");
|
||||
self.memory.write_f32(dest, f.sqrt())?;
|
||||
self.write_primval(dest, PrimVal::F32(f.sqrt()))?;
|
||||
}
|
||||
|
||||
"sqrtf64" => {
|
||||
let f = self.value_to_primval(args_ptrs[0], f64)?.expect_f64("sqrtf64 first arg not f64");
|
||||
self.memory.write_f64(dest, f.sqrt())?;
|
||||
self.write_primval(dest, PrimVal::F64(f.sqrt()))?;
|
||||
}
|
||||
|
||||
"size_of" => {
|
||||
let ty = substs.type_at(0);
|
||||
let size = self.type_size(ty) as u64;
|
||||
self.memory.write_uint(dest, size, pointer_size)?;
|
||||
let size_val = self.usize_primval(size);
|
||||
self.write_primval(dest, size_val)?;
|
||||
}
|
||||
|
||||
"size_of_val" => {
|
||||
let ty = substs.type_at(0);
|
||||
let (size, _) = self.size_and_align_of_dst(ty, args_ptrs[0])?;
|
||||
self.memory.write_uint(dest, size, pointer_size)?;
|
||||
let size_val = self.usize_primval(size);
|
||||
self.write_primval(dest, size_val)?;
|
||||
}
|
||||
"type_name" => {
|
||||
let ty = substs.type_at(0);
|
||||
@ -194,7 +230,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
"type_id" => {
|
||||
let ty = substs.type_at(0);
|
||||
let n = self.tcx.type_id_hash(ty);
|
||||
self.memory.write_uint(dest, n, 8)?;
|
||||
self.write_primval(dest, PrimVal::U64(n))?;
|
||||
}
|
||||
|
||||
"transmute" => {
|
||||
@ -202,20 +238,24 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
self.write_value(args_ptrs[0], dest, ty)?;
|
||||
}
|
||||
|
||||
"try" => unimplemented!(),
|
||||
"uninit" => {
|
||||
// FIXME(solson)
|
||||
let dest = dest.to_ptr();
|
||||
|
||||
"uninit" => self.memory.mark_definedness(dest, dest_layout.size(&self.tcx.data_layout).bytes() as usize, false)?,
|
||||
let size = dest_layout.size(&self.tcx.data_layout).bytes() as usize;
|
||||
self.memory.mark_definedness(dest, size, false)?;
|
||||
}
|
||||
|
||||
"volatile_load" => {
|
||||
let ty = substs.type_at(0);
|
||||
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
|
||||
self.move_(ptr, dest, ty)?;
|
||||
self.write_value(Value::ByRef(ptr), dest, ty)?;
|
||||
}
|
||||
|
||||
"volatile_store" => {
|
||||
let ty = substs.type_at(0);
|
||||
let dest = args_ptrs[0].read_ptr(&self.memory)?;
|
||||
self.write_value(args_ptrs[1], dest, ty)?;
|
||||
self.write_value_to_ptr(args_ptrs[1], dest, ty)?;
|
||||
}
|
||||
|
||||
name => return Err(EvalError::Unimplemented(format!("unimplemented intrinsic: {}", name))),
|
||||
|
@ -12,7 +12,7 @@ use syntax::{ast, attr};
|
||||
use error::{EvalError, EvalResult};
|
||||
use memory::Pointer;
|
||||
use primval::PrimVal;
|
||||
use super::{EvalContext, IntegerExt, StackPopCleanup};
|
||||
use super::{EvalContext, Lvalue, IntegerExt, StackPopCleanup};
|
||||
use super::value::Value;
|
||||
|
||||
mod intrinsics;
|
||||
@ -76,7 +76,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
Call { ref func, ref args, ref destination, .. } => {
|
||||
let destination = match *destination {
|
||||
Some((ref lv, target)) => Some((self.eval_lvalue(lv)?.to_ptr(), target)),
|
||||
Some((ref lv, target)) => Some((self.eval_lvalue(lv)?, target)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
@ -143,7 +143,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
def_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
fn_ty: &'tcx BareFnTy,
|
||||
destination: Option<(Pointer, mir::BasicBlock)>,
|
||||
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||
arg_operands: &[mir::Operand<'tcx>],
|
||||
span: Span,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
@ -184,15 +184,34 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
};
|
||||
|
||||
let mir = self.load_mir(resolved_def_id)?;
|
||||
let (return_ptr, return_to_block) = match destination {
|
||||
Some((ptr, block)) => (ptr, StackPopCleanup::Goto(block)),
|
||||
None => (Pointer::never_ptr(), StackPopCleanup::None),
|
||||
let (return_lvalue, return_to_block) = match destination {
|
||||
Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
|
||||
None => {
|
||||
// FIXME(solson)
|
||||
let lvalue = Lvalue::from_ptr(Pointer::never_ptr());
|
||||
(lvalue, StackPopCleanup::None)
|
||||
}
|
||||
};
|
||||
self.push_stack_frame(resolved_def_id, span, mir, resolved_substs, return_ptr, return_to_block)?;
|
||||
|
||||
self.push_stack_frame(
|
||||
resolved_def_id,
|
||||
span,
|
||||
mir,
|
||||
resolved_substs,
|
||||
return_lvalue,
|
||||
return_to_block
|
||||
)?;
|
||||
|
||||
for (i, (arg_val, arg_ty)) in args.into_iter().enumerate() {
|
||||
// argument start at index 1, since index 0 is reserved for the return allocation
|
||||
let dest = self.frame().locals[i + 1];
|
||||
|
||||
// FIXME(solson)
|
||||
let dest = match dest {
|
||||
Value::ByRef(p) => Lvalue::from_ptr(p),
|
||||
_ => bug!("all locals should be ByRef until I finish refactoring"),
|
||||
};
|
||||
|
||||
self.write_value(arg_val, dest, arg_ty)?;
|
||||
}
|
||||
|
||||
@ -245,7 +264,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
dest: Pointer,
|
||||
dest: Lvalue,
|
||||
dest_size: usize,
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
let name = self.tcx.item_name(def_id);
|
||||
@ -269,10 +288,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
match &link_name[..] {
|
||||
"__rust_allocate" => {
|
||||
let size = self.value_to_primval(args[0], usize)?.expect_uint("__rust_allocate first arg not usize");
|
||||
let align = self.value_to_primval(args[1], usize)?.expect_uint("__rust_allocate second arg not usize");
|
||||
let size = self.value_to_primval(args[0], usize)?
|
||||
.expect_uint("__rust_allocate first arg not usize");
|
||||
let align = self.value_to_primval(args[1], usize)?
|
||||
.expect_uint("__rust_allocate second arg not usize");
|
||||
let ptr = self.memory.allocate(size as usize, align as usize)?;
|
||||
self.memory.write_ptr(dest, ptr)?;
|
||||
self.write_primval(dest, PrimVal::Ptr(ptr))?;
|
||||
}
|
||||
|
||||
"__rust_reallocate" => {
|
||||
@ -280,7 +301,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let size = self.value_to_primval(args[2], usize)?.expect_uint("__rust_reallocate third arg not usize");
|
||||
let align = self.value_to_primval(args[3], usize)?.expect_uint("__rust_reallocate fourth arg not usize");
|
||||
let new_ptr = self.memory.reallocate(ptr, size as usize, align as usize)?;
|
||||
self.memory.write_ptr(dest, new_ptr)?;
|
||||
self.write_primval(dest, PrimVal::Ptr(new_ptr))?;
|
||||
}
|
||||
|
||||
"memcmp" => {
|
||||
@ -300,7 +321,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
self.memory.write_int(dest, result, dest_size)?;
|
||||
self.write_primval(dest, PrimVal::int_with_size(result, dest_size))?;
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use memory::{Memory, Pointer};
|
||||
use error::EvalResult;
|
||||
use memory::{Memory, Pointer};
|
||||
use primval::PrimVal;
|
||||
|
||||
/// A `Value` represents a single self-contained Rust value.
|
||||
@ -11,15 +11,14 @@ use primval::PrimVal;
|
||||
/// 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)]
|
||||
pub(super) enum Value {
|
||||
pub enum Value {
|
||||
ByRef(Pointer),
|
||||
ByVal(PrimVal),
|
||||
ByValPair(PrimVal, PrimVal),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
|
||||
pub(super) fn read_ptr<'a, 'tcx: 'a>(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
|
||||
impl<'a, 'tcx: 'a> Value {
|
||||
pub(super) fn read_ptr(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
|
||||
use self::Value::*;
|
||||
match *self {
|
||||
ByRef(ptr) => mem.read_ptr(ptr),
|
||||
@ -30,7 +29,7 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn expect_vtable<'a, 'tcx: 'a>(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
|
||||
pub(super) fn expect_vtable(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
|
||||
use self::Value::*;
|
||||
match *self {
|
||||
ByRef(ptr) => mem.read_ptr(ptr.offset(mem.pointer_size() as isize)),
|
||||
@ -39,7 +38,7 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn expect_slice_len<'a, 'tcx: 'a>(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, u64> {
|
||||
pub(super) fn expect_slice_len(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, u64> {
|
||||
use self::Value::*;
|
||||
match *self {
|
||||
ByRef(ptr) => mem.read_usize(ptr.offset(mem.pointer_size() as isize)),
|
||||
|
@ -60,6 +60,28 @@ impl PrimVal {
|
||||
_ => bug!("{}", error_msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uint_with_size(n: u64, size: usize) -> Self {
|
||||
use self::PrimVal::*;
|
||||
match size {
|
||||
1 => U8(n as u8),
|
||||
2 => U16(n as u16),
|
||||
4 => U32(n as u32),
|
||||
8 => U64(n),
|
||||
_ => bug!("can't make uint ({}) with size {}", n, size),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn int_with_size(n: i64, size: usize) -> Self {
|
||||
use self::PrimVal::*;
|
||||
match size {
|
||||
1 => I8(n as i8),
|
||||
2 => I16(n as i16),
|
||||
4 => I32(n as i32),
|
||||
8 => I64(n),
|
||||
_ => bug!("can't make int ({}) with size {}", n, size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the result of the operation and whether the operation overflowed
|
||||
|
@ -1,9 +0,0 @@
|
||||
#![feature(start)]
|
||||
|
||||
#[start]
|
||||
fn foo(nargs: isize, args: *const *const u8) -> isize {
|
||||
if nargs > 0 {
|
||||
assert!(unsafe{*args} as usize != 0);
|
||||
}
|
||||
0
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user