diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 81db48fe129..5cbad8c4f12 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -23,7 +23,7 @@ pub trait EvalContextExt<'tcx> { &mut self, def_id: DefId, arg_operands: &[mir::Operand<'tcx>], - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx>; @@ -33,7 +33,7 @@ pub trait EvalContextExt<'tcx> { fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, + destination: Option<(Lvalue, mir::BasicBlock)>, arg_operands: &[mir::Operand<'tcx>], sig: ty::FnSig<'tcx>, path: String, @@ -42,7 +42,7 @@ pub trait EvalContextExt<'tcx> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, + destination: Option<(Lvalue, mir::BasicBlock)>, arg_operands: &[mir::Operand<'tcx>], span: Span, sig: ty::FnSig<'tcx>, @@ -53,7 +53,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, + destination: Option<(Lvalue, mir::BasicBlock)>, arg_operands: &[mir::Operand<'tcx>], span: Span, sig: ty::FnSig<'tcx>, @@ -89,7 +89,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> &mut self, def_id: DefId, arg_operands: &[mir::Operand<'tcx>], - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx> { @@ -329,8 +329,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> if let Ok(instance) = self.resolve_path(path) { let cid = GlobalId { instance, promoted: None }; // compute global if not cached - let val = match self.globals.get(&cid).map(|glob| glob.value) { - Some(value) => self.value_to_primval(value, usize)?.to_u64()?, + let val = match self.globals.get(&cid).map(|&ptr| ptr) { + Some(ptr) => self.value_to_primval(Value::by_ref(ptr.into()), usize)?.to_u64()?, None => eval_body_as_primval(self.tcx, instance)?.0.to_u64()?, }; if val == name { @@ -459,7 +459,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, + destination: Option<(Lvalue, mir::BasicBlock)>, arg_operands: &[mir::Operand<'tcx>], sig: ty::FnSig<'tcx>, path: String, diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 4cdad350b43..053b2da86f7 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> { &mut self, instance: ty::Instance<'tcx>, args: &[mir::Operand<'tcx>], - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, dest_layout: &'tcx Layout, target: mir::BasicBlock, @@ -30,7 +30,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> &mut self, instance: ty::Instance<'tcx>, args: &[mir::Operand<'tcx>], - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, dest_layout: &'tcx Layout, target: mir::BasicBlock, @@ -291,7 +291,6 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?, Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned: true } => self.memory.write_repeat(ptr, 0, size)?, Lvalue::Ptr { .. } => bug!("init intrinsic tried to write to fat or unaligned ptr target"), - Lvalue::Global(cid) => self.modify_global(cid, init)?, } } @@ -469,7 +468,6 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned: true } => self.memory.mark_definedness(ptr, size, false)?, Lvalue::Ptr { .. } => bug!("uninit intrinsic tried to write to fat or unaligned ptr target"), - Lvalue::Global(cid) => self.modify_global(cid, uninit)?, } } diff --git a/miri/lib.rs b/miri/lib.rs index c887890fabf..1dc1682b17f 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -167,7 +167,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, + destination: Option<(Lvalue, mir::BasicBlock)>, arg_operands: &[mir::Operand<'tcx>], span: Span, sig: ty::FnSig<'tcx>, @@ -179,7 +179,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[mir::Operand<'tcx>], - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: ty::Ty<'tcx>, dest_layout: &'tcx Layout, target: mir::BasicBlock, diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 51f18bccf43..f55c94e67c4 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -7,9 +7,10 @@ use syntax::codemap::Span; use super::{ EvalResult, EvalError, EvalErrorKind, - Global, GlobalId, Lvalue, + GlobalId, Lvalue, Value, PrimVal, EvalContext, StackPopCleanup, + Kind, }; use rustc_const_math::ConstInt; @@ -30,7 +31,10 @@ pub fn eval_body_as_primval<'a, 'tcx>( let mir = ecx.load_mir(instance.def)?; if !ecx.globals.contains_key(&cid) { - ecx.globals.insert(cid, Global::uninitialized(mir.return_ty)); + let size = ecx.type_size_with_substs(mir.return_ty, instance.substs)?.expect("unsized global"); + let align = ecx.type_align_with_substs(mir.return_ty, instance.substs)?; + let ptr = ecx.memory.allocate(size, align, Kind::UninitializedStatic)?; + ecx.globals.insert(cid, ptr); let mutable = !mir.return_ty.is_freeze( ecx.tcx, ty::ParamEnv::empty(Reveal::All), @@ -47,13 +51,13 @@ pub fn eval_body_as_primval<'a, 'tcx>( instance, mir.span, mir, - Lvalue::Global(cid), + Lvalue::from_ptr(ptr), cleanup, )?; while ecx.step()? {} } - let value = ecx.globals.get(&cid).expect("global not cached").value; + let value = Value::by_ref(ecx.globals.get(&cid).expect("global not cached").into()); Ok((ecx.value_to_primval(value, mir.return_ty)?, mir.return_ty)) } @@ -132,7 +136,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator { fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, + destination: Option<(Lvalue, mir::BasicBlock)>, _arg_operands: &[mir::Operand<'tcx>], span: Span, _sig: ty::FnSig<'tcx>, @@ -168,7 +172,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator { _ecx: &mut EvalContext<'a, 'tcx, Self>, _instance: ty::Instance<'tcx>, _args: &[mir::Operand<'tcx>], - _dest: Lvalue<'tcx>, + _dest: Lvalue, _dest_ty: Ty<'tcx>, _dest_layout: &'tcx layout::Layout, _target: mir::BasicBlock, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c5ca9712955..beeb07b4ce1 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -18,7 +18,7 @@ use syntax::abi::Abi; use super::{ EvalError, EvalResult, EvalErrorKind, - Global, GlobalId, Lvalue, LvalueExtra, + GlobalId, Lvalue, LvalueExtra, Memory, MemoryPointer, HasMemory, Kind as MemoryKind, operator, @@ -41,7 +41,7 @@ pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> { pub(crate) suspended: HashMap>>, /// Precomputed statics, constants and promoteds. - pub globals: HashMap, Global<'tcx>>, + pub globals: HashMap, MemoryPointer>, /// The virtual call stack. pub(crate) stack: Vec>, @@ -78,7 +78,7 @@ pub struct Frame<'tcx> { pub return_to_block: StackPopCleanup, /// The location where the result of the current stack frame should be written to. - pub return_lvalue: Lvalue<'tcx>, + pub return_lvalue: Lvalue, /// The list of locals for this stack frame, stored in order as /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option`s. @@ -386,7 +386,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { self.type_align_with_substs(ty, self.substs()) } - fn type_size_with_substs( + pub fn type_size_with_substs( &self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>, @@ -399,7 +399,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } - fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, u64> { + pub fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, u64> { self.type_layout_with_substs(ty, substs).map(|layout| layout.align(&self.tcx.data_layout).abi()) } @@ -419,7 +419,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { instance: ty::Instance<'tcx>, span: codemap::Span, mir: &'tcx mir::Mir<'tcx>, - return_lvalue: Lvalue<'tcx>, + return_lvalue: Lvalue, return_to_block: StackPopCleanup, ) -> EvalResult<'tcx> { ::log_settings::settings().indentation += 1; @@ -485,31 +485,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { self.memory.set_cur_frame(cur_frame); } match frame.return_to_block { - StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Global(id) = frame.return_lvalue { - let global_value = self.globals.get_mut(&id) - .expect("global should have been cached (static)"); - match global_value.value { - // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions - Value::ByRef { ptr, aligned: _aligned } => - // Alignment does not matter for this call - self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, mutable)?, - Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val { - self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?; - }, - Value::ByValPair(val1, val2) => { - if let PrimVal::Ptr(ptr) = val1 { - self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?; - } - if let PrimVal::Ptr(ptr) = val2 { - self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?; - } - }, - } - // see comment on `initialized` field - assert!(!global_value.initialized); - global_value.initialized = true; - assert_eq!(global_value.mutable, Mutability::Mutable); - global_value.mutable = mutable; + StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Ptr{ ptr, .. } = frame.return_lvalue { + // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions + self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, mutable)? } else { bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue); }, @@ -543,7 +521,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn assign_discr_and_fields( &mut self, - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, discr_offset: u64, operands: &[mir::Operand<'tcx>], @@ -568,7 +546,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn assign_fields( &mut self, - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, operands: &[mir::Operand<'tcx>], ) -> EvalResult<'tcx> { @@ -1046,7 +1024,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Literal::Item { def_id, substs } => { let instance = self.resolve_associated_const(def_id, substs); let cid = GlobalId { instance, promoted: None }; - self.globals.get(&cid).expect("static/const not cached").value + Value::by_ref(self.globals.get(&cid).expect("static/const not cached").into()) } Literal::Promoted { index } => { @@ -1054,7 +1032,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { instance: self.frame().instance, promoted: Some(index), }; - self.globals.get(&cid).expect("promoted not cached").value + Value::by_ref(self.globals.get(&cid).expect("promoted not cached").into()) } }; @@ -1076,8 +1054,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn force_allocation( &mut self, - lvalue: Lvalue<'tcx>, - ) -> EvalResult<'tcx, Lvalue<'tcx>> { + lvalue: Lvalue, + ) -> EvalResult<'tcx, Lvalue> { let new_lvalue = match lvalue { Lvalue::Local { frame, local } => { // -1 since we don't store the return value @@ -1098,28 +1076,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } Lvalue::Ptr { .. } => lvalue, - Lvalue::Global(cid) => { - let global_val = self.globals.get(&cid).expect("global not cached").clone(); - match global_val.value { - Value::ByRef { ptr, aligned } => - Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None }, - _ => { - let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.instance.substs)?; - self.memory.mark_static(ptr.alloc_id); - self.write_value_to_ptr(global_val.value, ptr.into(), global_val.ty)?; - // see comment on `initialized` field - if global_val.initialized { - self.memory.mark_static_initalized(ptr.alloc_id, global_val.mutable)?; - } - let lval = self.globals.get_mut(&cid).expect("already checked"); - *lval = Global { - value: Value::by_ref(ptr.into()), - .. global_val - }; - Lvalue::from_ptr(ptr) - }, - } - } }; Ok(new_lvalue) } @@ -1149,7 +1105,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn write_null( &mut self, - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx> { self.write_primval(dest, PrimVal::Bytes(0), dest_ty) @@ -1157,7 +1113,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn write_ptr( &mut self, - dest: Lvalue<'tcx>, + dest: Lvalue, val: Pointer, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx> { @@ -1166,7 +1122,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn write_primval( &mut self, - dest: Lvalue<'tcx>, + dest: Lvalue, val: PrimVal, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx> { @@ -1176,7 +1132,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn write_value( &mut self, src_val: Value, - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx> { //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty); @@ -1185,21 +1141,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // correct if we never look at this data with the wrong type. match dest { - Lvalue::Global(cid) => { - let dest = self.globals.get_mut(&cid).expect("global should be cached").clone(); - if dest.mutable == Mutability::Immutable { - return err!(ModifiedConstantMemory); - } - let write_dest = |this: &mut Self, val| { - *this.globals.get_mut(&cid).expect("already checked") = Global { - value: val, - ..dest - }; - Ok(()) - }; - self.write_value_possibly_by_val(src_val, write_dest, dest.value, dest_ty) - }, - Lvalue::Ptr { ptr, extra, aligned } => { assert_eq!(extra, LvalueExtra::None); self.write_maybe_aligned_mut(aligned, @@ -1542,7 +1483,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { &mut self, src: Value, src_ty: Ty<'tcx>, - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, sty: Ty<'tcx>, dty: Ty<'tcx>, @@ -1578,7 +1519,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { &mut self, src: Value, src_ty: Ty<'tcx>, - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx> { match (&src_ty.sty, &dest_ty.sty) { @@ -1640,7 +1581,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } - pub fn dump_local(&self, lvalue: Lvalue<'tcx>) { + pub fn dump_local(&self, lvalue: Lvalue) { // Debug output if let Lvalue::Local { frame, local } = lvalue { let mut allocs = Vec::new(); @@ -1680,20 +1621,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } - /// Convenience function to ensure correct usage of globals and code-sharing with locals. - pub fn modify_global(&mut self, cid: GlobalId<'tcx>, f: F) -> EvalResult<'tcx> - where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>, - { - let mut val = self.globals.get(&cid).expect("global not cached").clone(); - if val.mutable == Mutability::Immutable { - return err!(ModifiedConstantMemory); - } - val.value = f(self, val.value)?; - *self.globals.get_mut(&cid).expect("already checked") = val; - Ok(()) - } - - /// Convenience function to ensure correct usage of locals and code-sharing with globals. + /// Convenience function to ensure correct usage of locals pub fn modify_local( &mut self, frame: usize, diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs index 8722c96dbec..4485e936b1e 100644 --- a/src/librustc_mir/interpret/lvalue.rs +++ b/src/librustc_mir/interpret/lvalue.rs @@ -2,7 +2,6 @@ use rustc::mir; use rustc::ty::layout::{Size, Align}; use rustc::ty::{self, Ty}; use rustc_data_structures::indexed_vec::Idx; -use syntax::ast::Mutability; use super::{ EvalResult, @@ -13,7 +12,7 @@ use super::{ }; #[derive(Copy, Clone, Debug)] -pub enum Lvalue<'tcx> { +pub enum Lvalue { /// An lvalue referring to a value allocated in the `Memory` system. Ptr { /// An lvalue may have an invalid (integral or undef) pointer, @@ -31,9 +30,6 @@ pub enum Lvalue<'tcx> { frame: usize, local: mir::Local, }, - - /// An lvalue referring to a global - Global(GlobalId<'tcx>), } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -55,19 +51,7 @@ pub struct GlobalId<'tcx> { pub promoted: Option, } -#[derive(Clone, Debug)] -pub struct Global<'tcx> { - pub value: Value, - /// Only used in `force_allocation` to ensure we don't mark the memory - /// before the static is initialized. It is possible to convert a - /// global which initially is `Value::ByVal(PrimVal::Undef)` and gets - /// lifted to an allocation before the static is fully initialized - pub(super) initialized: bool, - pub(super) mutable: Mutability, - pub(super) ty: Ty<'tcx>, -} - -impl<'tcx> Lvalue<'tcx> { +impl<'tcx> Lvalue { /// Produces an Lvalue that will error if attempted to be read from pub fn undef() -> Self { Self::from_primval_ptr(PrimVal::Undef.into()) @@ -113,26 +97,6 @@ impl<'tcx> Lvalue<'tcx> { } } -impl<'tcx> Global<'tcx> { - pub(super) fn uninitialized(ty: Ty<'tcx>) -> Self { - Global { - value: Value::ByVal(PrimVal::Undef), - mutable: Mutability::Mutable, - ty, - initialized: false, - } - } - - pub(super) fn initialized(ty: Ty<'tcx>, value: Value, mutable: Mutability) -> Self { - Global { - value, - mutable, - ty, - initialized: true, - } - } -} - impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { /// Reads a value from the lvalue without going through the intermediate step of obtaining /// a `miri::Lvalue` @@ -147,7 +111,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Static(ref static_) => { let instance = ty::Instance::mono(self.tcx, static_.def_id); let cid = GlobalId { instance, promoted: None }; - Ok(Some(self.globals.get(&cid).expect("global not cached").value)) + Ok(Some(Value::by_ref(self.globals.get(&cid).expect("global not cached").into()))) }, Projection(ref proj) => self.try_read_lvalue_projection(proj), } @@ -195,7 +159,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { self.read_lvalue(lvalue) } - pub fn read_lvalue(&self, lvalue: Lvalue<'tcx>) -> EvalResult<'tcx, Value> { + pub fn read_lvalue(&self, lvalue: Lvalue) -> EvalResult<'tcx, Value> { match lvalue { Lvalue::Ptr { ptr, extra, aligned } => { assert_eq!(extra, LvalueExtra::None); @@ -204,13 +168,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Lvalue::Local { frame, local } => { self.stack[frame].get_local(local) } - Lvalue::Global(cid) => { - Ok(self.globals.get(&cid).expect("global not cached").value) - } } } - pub fn eval_lvalue(&mut self, mir_lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue<'tcx>> { + pub fn eval_lvalue(&mut self, mir_lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> { use rustc::mir::Lvalue::*; let lvalue = match *mir_lvalue { Local(mir::RETURN_POINTER) => self.frame().return_lvalue, @@ -218,7 +179,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Static(ref static_) => { let instance = ty::Instance::mono(self.tcx, static_.def_id); - Lvalue::Global(GlobalId { instance, promoted: None }) + let gid = GlobalId { instance, promoted: None }; + Lvalue::from_ptr(*self.globals.get(&gid).expect("uncached global")) } Projection(ref proj) => { @@ -237,11 +199,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn lvalue_field( &mut self, - base: Lvalue<'tcx>, + base: Lvalue, field_index: usize, base_ty: Ty<'tcx>, field_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Lvalue<'tcx>> { + ) -> EvalResult<'tcx, Lvalue> { let base_layout = self.type_layout(base_ty)?; use rustc::ty::layout::Layout::*; let (offset, packed) = match *base_layout { @@ -312,16 +274,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Value::ByValPair(..) | Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(), }, - Lvalue::Global(cid) => match self.globals.get(&cid).expect("uncached global").value { - // in case the type has a single field, just return the value - Value::ByVal(_) if self.get_field_count(base_ty).map(|c| c == 1).unwrap_or(false) => { - assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0"); - return Ok(base); - }, - Value::ByRef{..} | - Value::ByValPair(..) | - Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(), - }, }; let offset = match base_extra { @@ -352,7 +304,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Ok(Lvalue::Ptr { ptr, extra, aligned: aligned && !packed }) } - pub(super) fn val_to_lvalue(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue<'tcx>> { + pub(super) fn val_to_lvalue(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue> { Ok(match self.tcx.struct_tail(ty).sty { ty::TyDynamic(..) => { let (ptr, vtable) = val.into_ptr_vtable_pair(&self.memory)?; @@ -366,7 +318,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }) } - pub(super) fn lvalue_index(&mut self, base: Lvalue<'tcx>, outer_ty: Ty<'tcx>, n: u64) -> EvalResult<'tcx, Lvalue<'tcx>> { + pub(super) fn lvalue_index(&mut self, base: Lvalue, outer_ty: Ty<'tcx>, n: u64) -> EvalResult<'tcx, Lvalue> { // Taking the outer type here may seem odd; it's needed because for array types, the outer type gives away the length. let base = self.force_allocation(base)?; let (base_ptr, _, aligned) = base.to_ptr_extra_aligned(); @@ -380,10 +332,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub(super) fn eval_lvalue_projection( &mut self, - base: Lvalue<'tcx>, + base: Lvalue, base_ty: Ty<'tcx>, proj_elem: &mir::ProjectionElem<'tcx, mir::Operand<'tcx>, Ty<'tcx>>, - ) -> EvalResult<'tcx, Lvalue<'tcx>> { + ) -> EvalResult<'tcx, Lvalue> { use rustc::mir::ProjectionElem::*; let (ptr, extra, aligned) = match *proj_elem { Field(field, field_ty) => { diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 0150a6c836d..c65c3f2e103 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -33,7 +33,7 @@ pub trait Machine<'tcx>: Sized { fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, + destination: Option<(Lvalue, mir::BasicBlock)>, arg_operands: &[mir::Operand<'tcx>], span: Span, sig: ty::FnSig<'tcx>, @@ -44,7 +44,7 @@ pub trait Machine<'tcx>: Sized { ecx: &mut EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[mir::Operand<'tcx>], - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: ty::Ty<'tcx>, dest_layout: &'tcx ty::layout::Layout, target: mir::BasicBlock, diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index c476046d385..1ea814d5714 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -234,12 +234,6 @@ pub struct Memory<'a, 'tcx, M: Machine<'tcx>> { /// The AllocId to assign to the next new regular allocation. Always incremented, never gets smaller. next_alloc_id: u64, - /// Set of statics, constants, promoteds, vtables, ... to prevent `mark_static_initalized` from - /// stepping out of its own allocations. This set only contains statics backed by an - /// allocation. If they are ByVal or ByValPair they are not here, but will be inserted once - /// they become ByRef. - static_alloc: HashSet, - /// Number of virtual bytes allocated. memory_usage: u64, @@ -280,7 +274,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { layout, memory_size: max_memory, memory_usage: 0, - static_alloc: HashSet::new(), literal_alloc_cache: HashMap::new(), reads_are_aligned: Cell::new(true), writes_are_aligned: Cell::new(true), @@ -859,18 +852,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { /// Reading and writing impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - /// mark an allocation as being the entry point to a static (see `static_alloc` field) - pub fn mark_static(&mut self, alloc_id: AllocId) { - trace!("mark_static: {:?}", alloc_id); - if !self.static_alloc.insert(alloc_id) { - bug!("tried to mark an allocation ({:?}) as static twice", alloc_id); - } - } /// mark an allocation pointed to by a static as static and initialized pub fn mark_inner_allocation(&mut self, alloc: AllocId, mutability: Mutability) -> EvalResult<'tcx> { // relocations into other statics are not "inner allocations" - if !self.static_alloc.contains(&alloc) { + if self.get(alloc).ok().map_or(false, |alloc| alloc.kind != Kind::UninitializedStatic) { self.mark_static_initalized(alloc, mutability)?; } Ok(()) diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 39a0c7d25f9..b2e5f134d34 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -38,7 +38,6 @@ pub use self::eval_context::{ pub use self::lvalue::{ Lvalue, LvalueExtra, - Global, GlobalId, }; diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index a9675d148d6..8880be6e848 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { op: mir::BinOp, left: &mir::Operand<'tcx>, right: &mir::Operand<'tcx>, - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx> { let (val, overflowed) = self.binop_with_overflow(op, left, right)?; @@ -54,7 +54,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { op: mir::BinOp, left: &mir::Operand<'tcx>, right: &mir::Operand<'tcx>, - dest: Lvalue<'tcx>, + dest: Lvalue, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx, bool> { let (val, overflowed) = self.binop_with_overflow(op, left, right)?; diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 56195998b9e..ca3c8490e7a 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -14,9 +14,8 @@ use rustc::ty::subst::Substs; use super::{ EvalResult, EvalContext, StackPopCleanup, TyAndPacked, - Global, GlobalId, Lvalue, - Value, PrimVal, - HasMemory, + GlobalId, Lvalue, + HasMemory, Kind, Machine, }; @@ -179,11 +178,18 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { if self.tcx.has_attr(def_id, "linkage") { // FIXME: check that it's `#[linkage = "extern_weak"]` trace!("Initializing an extern global with NULL"); - self.globals.insert(cid, Global::initialized(self.tcx.type_of(def_id), Value::ByVal(PrimVal::Bytes(0)), mutability)); + let ptr_size = self.memory.pointer_size(); + let ptr = self.memory.allocate(ptr_size, ptr_size, Kind::UninitializedStatic)?; + self.memory.write_usize(ptr, 0)?; + self.memory.mark_static_initalized(ptr.alloc_id, mutability)?; + self.globals.insert(cid, ptr); return Ok(false); } let mir = self.load_mir(instance.def)?; - self.globals.insert(cid, Global::uninitialized(mir.return_ty)); + let size = self.type_size_with_substs(mir.return_ty, substs)?.expect("unsized global"); + let align = self.type_align_with_substs(mir.return_ty, substs)?; + let ptr = self.memory.allocate(size, align, Kind::UninitializedStatic)?; + self.globals.insert(cid, ptr); let internally_mutable = !mir.return_ty.is_freeze( self.tcx, ty::ParamEnv::empty(Reveal::All), @@ -200,7 +206,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { instance, span, mir, - Lvalue::Global(cid), + Lvalue::from_ptr(ptr), cleanup, )?; Ok(true) @@ -256,13 +262,15 @@ impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b, } let mir = &self.mir.promoted[index]; self.try(|this| { - let ty = this.ecx.monomorphize(mir.return_ty, this.instance.substs); - this.ecx.globals.insert(cid, Global::uninitialized(ty)); + let size = this.ecx.type_size_with_substs(mir.return_ty, this.instance.substs)?.expect("unsized global"); + let align = this.ecx.type_align_with_substs(mir.return_ty, this.instance.substs)?; + let ptr = this.ecx.memory.allocate(size, align, Kind::UninitializedStatic)?; + this.ecx.globals.insert(cid, ptr); trace!("pushing stack frame for {:?}", index); this.ecx.push_stack_frame(this.instance, constant.span, mir, - Lvalue::Global(cid), + Lvalue::from_ptr(ptr), StackPopCleanup::MarkStatic(Mutability::Immutable), )?; Ok(true) diff --git a/src/librustc_mir/interpret/terminator/drop.rs b/src/librustc_mir/interpret/terminator/drop.rs index 5f4bc0b1bd9..527d5917b66 100644 --- a/src/librustc_mir/interpret/terminator/drop.rs +++ b/src/librustc_mir/interpret/terminator/drop.rs @@ -11,7 +11,7 @@ use interpret::{ }; impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub(crate) fn drop_lvalue(&mut self, lval: Lvalue<'tcx>, instance: ty::Instance<'tcx>, ty: Ty<'tcx>, span: Span) -> EvalResult<'tcx> { + pub(crate) fn drop_lvalue(&mut self, lval: Lvalue, instance: ty::Instance<'tcx>, ty: Ty<'tcx>, span: Span) -> EvalResult<'tcx> { trace!("drop_lvalue: {:#?}", lval); // We take the address of the object. This may well be unaligned, which is fine for us here. // However, unaligned accesses will probably make the actual drop implementation fail -- a problem shared diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index b9447a30ab1..a6412dedd3b 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -204,7 +204,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>, + destination: Option<(Lvalue, mir::BasicBlock)>, arg_operands: &[mir::Operand<'tcx>], span: Span, sig: ty::FnSig<'tcx>, diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs index 83931535e59..459309abda7 100644 --- a/src/librustc_mir/interpret/validation.rs +++ b/src/librustc_mir/interpret/validation.rs @@ -16,7 +16,7 @@ use super::{ Machine, }; -pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, Lvalue<'tcx>>; +pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, Lvalue>; #[derive(Copy, Clone, Debug)] enum ValidationMode { @@ -242,8 +242,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } } - Lvalue::Local { .. } | Lvalue::Global(..) => { - // These are not backed by memory, so we have nothing to do. + Lvalue::Local { .. } => { + // Not backed by memory, so we have nothing to do. } } } diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs index 88ffc57a8f0..cd1bde987fe 100644 --- a/src/librustc_mir/interpret/value.rs +++ b/src/librustc_mir/interpret/value.rs @@ -133,6 +133,12 @@ impl ::std::convert::From for Pointer { } } +impl<'a> ::std::convert::From<&'a MemoryPointer> for Pointer { + fn from(ptr: &'a MemoryPointer) -> Self { + PrimVal::Ptr(*ptr).into() + } +} + /// A `PrimVal` represents an immediate, primitive value existing outside of a /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes