statics are rare and constants are copied anyway.
Reading from a constant should then yield a `ByVal` again if possible.
&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>;
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,
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>,
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>,
&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> {
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 {
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,
&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,
&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,
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)?,
}
}
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)?,
}
}
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>,
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,
use super::{
EvalResult, EvalError, EvalErrorKind,
- Global, GlobalId, Lvalue,
+ GlobalId, Lvalue, Value,
PrimVal,
EvalContext, StackPopCleanup,
+ Kind,
};
use rustc_const_math::ConstInt;
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),
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))
}
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>,
_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,
use super::{
EvalError, EvalResult, EvalErrorKind,
- Global, GlobalId, Lvalue, LvalueExtra,
+ GlobalId, Lvalue, LvalueExtra,
Memory, MemoryPointer, HasMemory,
Kind as MemoryKind,
operator,
pub(crate) suspended: HashMap<DynamicLifetime, Vec<ValidationQuery<'tcx>>>,
/// Precomputed statics, constants and promoteds.
- pub globals: HashMap<GlobalId<'tcx>, Global<'tcx>>,
+ pub globals: HashMap<GlobalId<'tcx>, MemoryPointer>,
/// The virtual call stack.
pub(crate) stack: Vec<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<Value>`s.
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>,
}
}
- 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())
}
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;
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);
},
pub fn assign_discr_and_fields(
&mut self,
- dest: Lvalue<'tcx>,
+ dest: Lvalue,
dest_ty: Ty<'tcx>,
discr_offset: u64,
operands: &[mir::Operand<'tcx>],
pub fn assign_fields(
&mut self,
- dest: Lvalue<'tcx>,
+ dest: Lvalue,
dest_ty: Ty<'tcx>,
operands: &[mir::Operand<'tcx>],
) -> EvalResult<'tcx> {
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 } => {
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())
}
};
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
}
}
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)
}
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)
pub fn write_ptr(
&mut self,
- dest: Lvalue<'tcx>,
+ dest: Lvalue,
val: Pointer,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx> {
pub fn write_primval(
&mut self,
- dest: Lvalue<'tcx>,
+ dest: Lvalue,
val: PrimVal,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx> {
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);
// 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,
&mut self,
src: Value,
src_ty: Ty<'tcx>,
- dest: Lvalue<'tcx>,
+ dest: Lvalue,
dest_ty: Ty<'tcx>,
sty: Ty<'tcx>,
dty: Ty<'tcx>,
&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) {
}
}
- 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();
}
}
- /// Convenience function to ensure correct usage of globals and code-sharing with locals.
- pub fn modify_global<F>(&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<F>(
&mut self,
frame: usize,
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,
};
#[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,
frame: usize,
local: mir::Local,
},
-
- /// An lvalue referring to a global
- Global(GlobalId<'tcx>),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub promoted: Option<mir::Promoted>,
}
-#[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())
}
}
-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`
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),
}
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);
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,
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) => {
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 {
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 {
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)?;
})
}
- 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();
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) => {
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>,
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,
/// 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<AllocId>,
-
/// Number of virtual bytes allocated.
memory_usage: u64,
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),
/// 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(())
pub use self::lvalue::{
Lvalue,
LvalueExtra,
- Global,
GlobalId,
};
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)?;
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)?;
use super::{
EvalResult,
EvalContext, StackPopCleanup, TyAndPacked,
- Global, GlobalId, Lvalue,
- Value, PrimVal,
- HasMemory,
+ GlobalId, Lvalue,
+ HasMemory, Kind,
Machine,
};
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),
instance,
span,
mir,
- Lvalue::Global(cid),
+ Lvalue::from_ptr(ptr),
cleanup,
)?;
Ok(true)
}
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)
};
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
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>,
Machine,
};
-pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, Lvalue<'tcx>>;
+pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, Lvalue>;
#[derive(Copy, Clone, Debug)]
enum ValidationMode {
}
}
}
- 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.
}
}
}
}
}
+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