diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index b5d339dd9a7..dc787a7608c 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -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, + pub locals: Vec, //////////////////////////////////////////////////////////////////////////////// // 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> = iter::once(Ok(return_ptr)).chain(local_tys.skip(1).map(|ty| { + let locals: EvalResult<'tcx, Vec> = 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>( &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; diff --git a/src/interpreter/step.rs b/src/interpreter/step.rs index 77350504306..7888257141c 100644 --- a/src/interpreter/step.rs +++ b/src/interpreter/step.rs @@ -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 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)) }); } diff --git a/src/interpreter/terminator/intrinsics.rs b/src/interpreter/terminator/intrinsics.rs index 31e337924ad..5fd96426b79 100644 --- a/src/interpreter/terminator/intrinsics.rs +++ b/src/interpreter/terminator/intrinsics.rs @@ -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))), diff --git a/src/interpreter/terminator/mod.rs b/src/interpreter/terminator/mod.rs index 5c9123ba91e..b4559670405 100644 --- a/src/interpreter/terminator/mod.rs +++ b/src/interpreter/terminator/mod.rs @@ -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))?; } _ => { diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs index 87a0e15cf75..178dbac8401 100644 --- a/src/interpreter/value.rs +++ b/src/interpreter/value.rs @@ -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)), diff --git a/src/primval.rs b/src/primval.rs index 70934c2a549..26c1d715c4c 100644 --- a/src/primval.rs +++ b/src/primval.rs @@ -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 diff --git a/tests/run-pass/start_fn.rs b/tests/run-pass/start_fn.rs deleted file mode 100644 index 8b884e22fed..00000000000 --- a/tests/run-pass/start_fn.rs +++ /dev/null @@ -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 -}