Always allocate for globals
statics are rare and constants are copied anyway. Reading from a constant should then yield a `ByVal` again if possible.
This commit is contained in:
parent
4ba2b82f31
commit
181851fc6b
15 changed files with 91 additions and 210 deletions
|
@ -23,7 +23,7 @@ pub trait EvalContextExt<'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
arg_operands: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
dest_block: mir::BasicBlock,
|
dest_block: mir::BasicBlock,
|
||||||
) -> EvalResult<'tcx>;
|
) -> EvalResult<'tcx>;
|
||||||
|
@ -33,7 +33,7 @@ pub trait EvalContextExt<'tcx> {
|
||||||
fn call_missing_fn(
|
fn call_missing_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||||
arg_operands: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
sig: ty::FnSig<'tcx>,
|
sig: ty::FnSig<'tcx>,
|
||||||
path: String,
|
path: String,
|
||||||
|
@ -42,7 +42,7 @@ pub trait EvalContextExt<'tcx> {
|
||||||
fn eval_fn_call(
|
fn eval_fn_call(
|
||||||
&mut self,
|
&mut self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||||
arg_operands: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
span: Span,
|
span: Span,
|
||||||
sig: ty::FnSig<'tcx>,
|
sig: ty::FnSig<'tcx>,
|
||||||
|
@ -53,7 +53,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
|
||||||
fn eval_fn_call(
|
fn eval_fn_call(
|
||||||
&mut self,
|
&mut self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||||
arg_operands: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
span: Span,
|
span: Span,
|
||||||
sig: ty::FnSig<'tcx>,
|
sig: ty::FnSig<'tcx>,
|
||||||
|
@ -89,7 +89,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
|
||||||
&mut self,
|
&mut self,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
arg_operands: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
dest_block: mir::BasicBlock,
|
dest_block: mir::BasicBlock,
|
||||||
) -> EvalResult<'tcx> {
|
) -> 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) {
|
if let Ok(instance) = self.resolve_path(path) {
|
||||||
let cid = GlobalId { instance, promoted: None };
|
let cid = GlobalId { instance, promoted: None };
|
||||||
// compute global if not cached
|
// compute global if not cached
|
||||||
let val = match self.globals.get(&cid).map(|glob| glob.value) {
|
let val = match self.globals.get(&cid).map(|&ptr| ptr) {
|
||||||
Some(value) => self.value_to_primval(value, usize)?.to_u64()?,
|
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()?,
|
None => eval_body_as_primval(self.tcx, instance)?.0.to_u64()?,
|
||||||
};
|
};
|
||||||
if val == name {
|
if val == name {
|
||||||
|
@ -459,7 +459,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
|
||||||
fn call_missing_fn(
|
fn call_missing_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||||
arg_operands: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
sig: ty::FnSig<'tcx>,
|
sig: ty::FnSig<'tcx>,
|
||||||
path: String,
|
path: String,
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
args: &[mir::Operand<'tcx>],
|
args: &[mir::Operand<'tcx>],
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
dest_layout: &'tcx Layout,
|
dest_layout: &'tcx Layout,
|
||||||
target: mir::BasicBlock,
|
target: mir::BasicBlock,
|
||||||
|
@ -30,7 +30,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
|
||||||
&mut self,
|
&mut self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
args: &[mir::Operand<'tcx>],
|
args: &[mir::Operand<'tcx>],
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
dest_layout: &'tcx Layout,
|
dest_layout: &'tcx Layout,
|
||||||
target: mir::BasicBlock,
|
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::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 { 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::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 } =>
|
Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned: true } =>
|
||||||
self.memory.mark_definedness(ptr, size, false)?,
|
self.memory.mark_definedness(ptr, size, false)?,
|
||||||
Lvalue::Ptr { .. } => bug!("uninit intrinsic tried to write to fat or unaligned ptr target"),
|
Lvalue::Ptr { .. } => bug!("uninit intrinsic tried to write to fat or unaligned ptr target"),
|
||||||
Lvalue::Global(cid) => self.modify_global(cid, uninit)?,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ impl<'tcx> Machine<'tcx> for Evaluator {
|
||||||
fn eval_fn_call<'a>(
|
fn eval_fn_call<'a>(
|
||||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||||
arg_operands: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
span: Span,
|
span: Span,
|
||||||
sig: ty::FnSig<'tcx>,
|
sig: ty::FnSig<'tcx>,
|
||||||
|
@ -179,7 +179,7 @@ impl<'tcx> Machine<'tcx> for Evaluator {
|
||||||
ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Self>,
|
ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Self>,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
args: &[mir::Operand<'tcx>],
|
args: &[mir::Operand<'tcx>],
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: ty::Ty<'tcx>,
|
dest_ty: ty::Ty<'tcx>,
|
||||||
dest_layout: &'tcx Layout,
|
dest_layout: &'tcx Layout,
|
||||||
target: mir::BasicBlock,
|
target: mir::BasicBlock,
|
||||||
|
|
|
@ -7,9 +7,10 @@ use syntax::codemap::Span;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
EvalResult, EvalError, EvalErrorKind,
|
EvalResult, EvalError, EvalErrorKind,
|
||||||
Global, GlobalId, Lvalue,
|
GlobalId, Lvalue, Value,
|
||||||
PrimVal,
|
PrimVal,
|
||||||
EvalContext, StackPopCleanup,
|
EvalContext, StackPopCleanup,
|
||||||
|
Kind,
|
||||||
};
|
};
|
||||||
|
|
||||||
use rustc_const_math::ConstInt;
|
use rustc_const_math::ConstInt;
|
||||||
|
@ -30,7 +31,10 @@ pub fn eval_body_as_primval<'a, 'tcx>(
|
||||||
|
|
||||||
let mir = ecx.load_mir(instance.def)?;
|
let mir = ecx.load_mir(instance.def)?;
|
||||||
if !ecx.globals.contains_key(&cid) {
|
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(
|
let mutable = !mir.return_ty.is_freeze(
|
||||||
ecx.tcx,
|
ecx.tcx,
|
||||||
ty::ParamEnv::empty(Reveal::All),
|
ty::ParamEnv::empty(Reveal::All),
|
||||||
|
@ -47,13 +51,13 @@ pub fn eval_body_as_primval<'a, 'tcx>(
|
||||||
instance,
|
instance,
|
||||||
mir.span,
|
mir.span,
|
||||||
mir,
|
mir,
|
||||||
Lvalue::Global(cid),
|
Lvalue::from_ptr(ptr),
|
||||||
cleanup,
|
cleanup,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
while ecx.step()? {}
|
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))
|
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>(
|
fn eval_fn_call<'a>(
|
||||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||||
_arg_operands: &[mir::Operand<'tcx>],
|
_arg_operands: &[mir::Operand<'tcx>],
|
||||||
span: Span,
|
span: Span,
|
||||||
_sig: ty::FnSig<'tcx>,
|
_sig: ty::FnSig<'tcx>,
|
||||||
|
@ -168,7 +172,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator {
|
||||||
_ecx: &mut EvalContext<'a, 'tcx, Self>,
|
_ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||||
_instance: ty::Instance<'tcx>,
|
_instance: ty::Instance<'tcx>,
|
||||||
_args: &[mir::Operand<'tcx>],
|
_args: &[mir::Operand<'tcx>],
|
||||||
_dest: Lvalue<'tcx>,
|
_dest: Lvalue,
|
||||||
_dest_ty: Ty<'tcx>,
|
_dest_ty: Ty<'tcx>,
|
||||||
_dest_layout: &'tcx layout::Layout,
|
_dest_layout: &'tcx layout::Layout,
|
||||||
_target: mir::BasicBlock,
|
_target: mir::BasicBlock,
|
||||||
|
|
|
@ -18,7 +18,7 @@ use syntax::abi::Abi;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
EvalError, EvalResult, EvalErrorKind,
|
EvalError, EvalResult, EvalErrorKind,
|
||||||
Global, GlobalId, Lvalue, LvalueExtra,
|
GlobalId, Lvalue, LvalueExtra,
|
||||||
Memory, MemoryPointer, HasMemory,
|
Memory, MemoryPointer, HasMemory,
|
||||||
Kind as MemoryKind,
|
Kind as MemoryKind,
|
||||||
operator,
|
operator,
|
||||||
|
@ -41,7 +41,7 @@ pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> {
|
||||||
pub(crate) suspended: HashMap<DynamicLifetime, Vec<ValidationQuery<'tcx>>>,
|
pub(crate) suspended: HashMap<DynamicLifetime, Vec<ValidationQuery<'tcx>>>,
|
||||||
|
|
||||||
/// Precomputed statics, constants and promoteds.
|
/// Precomputed statics, constants and promoteds.
|
||||||
pub globals: HashMap<GlobalId<'tcx>, Global<'tcx>>,
|
pub globals: HashMap<GlobalId<'tcx>, MemoryPointer>,
|
||||||
|
|
||||||
/// The virtual call stack.
|
/// The virtual call stack.
|
||||||
pub(crate) stack: Vec<Frame<'tcx>>,
|
pub(crate) stack: Vec<Frame<'tcx>>,
|
||||||
|
@ -78,7 +78,7 @@ pub struct Frame<'tcx> {
|
||||||
pub return_to_block: StackPopCleanup,
|
pub return_to_block: StackPopCleanup,
|
||||||
|
|
||||||
/// The location where the result of the current stack frame should be written to.
|
/// 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
|
/// The list of locals for this stack frame, stored in order as
|
||||||
/// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
|
/// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
|
||||||
|
@ -386,7 +386,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
self.type_align_with_substs(ty, self.substs())
|
self.type_align_with_substs(ty, self.substs())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_size_with_substs(
|
pub fn type_size_with_substs(
|
||||||
&self,
|
&self,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
substs: &'tcx Substs<'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())
|
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>,
|
instance: ty::Instance<'tcx>,
|
||||||
span: codemap::Span,
|
span: codemap::Span,
|
||||||
mir: &'tcx mir::Mir<'tcx>,
|
mir: &'tcx mir::Mir<'tcx>,
|
||||||
return_lvalue: Lvalue<'tcx>,
|
return_lvalue: Lvalue,
|
||||||
return_to_block: StackPopCleanup,
|
return_to_block: StackPopCleanup,
|
||||||
) -> EvalResult<'tcx> {
|
) -> EvalResult<'tcx> {
|
||||||
::log_settings::settings().indentation += 1;
|
::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);
|
self.memory.set_cur_frame(cur_frame);
|
||||||
}
|
}
|
||||||
match frame.return_to_block {
|
match frame.return_to_block {
|
||||||
StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Global(id) = frame.return_lvalue {
|
StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Ptr{ ptr, .. } = frame.return_lvalue {
|
||||||
let global_value = self.globals.get_mut(&id)
|
// FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
|
||||||
.expect("global should have been cached (static)");
|
self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, mutable)?
|
||||||
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;
|
|
||||||
} else {
|
} else {
|
||||||
bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue);
|
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(
|
pub fn assign_discr_and_fields(
|
||||||
&mut self,
|
&mut self,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
discr_offset: u64,
|
discr_offset: u64,
|
||||||
operands: &[mir::Operand<'tcx>],
|
operands: &[mir::Operand<'tcx>],
|
||||||
|
@ -568,7 +546,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
|
|
||||||
pub fn assign_fields(
|
pub fn assign_fields(
|
||||||
&mut self,
|
&mut self,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
operands: &[mir::Operand<'tcx>],
|
operands: &[mir::Operand<'tcx>],
|
||||||
) -> EvalResult<'tcx> {
|
) -> EvalResult<'tcx> {
|
||||||
|
@ -1046,7 +1024,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
Literal::Item { def_id, substs } => {
|
Literal::Item { def_id, substs } => {
|
||||||
let instance = self.resolve_associated_const(def_id, substs);
|
let instance = self.resolve_associated_const(def_id, substs);
|
||||||
let cid = GlobalId { instance, promoted: None };
|
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 } => {
|
Literal::Promoted { index } => {
|
||||||
|
@ -1054,7 +1032,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
instance: self.frame().instance,
|
instance: self.frame().instance,
|
||||||
promoted: Some(index),
|
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(
|
pub fn force_allocation(
|
||||||
&mut self,
|
&mut self,
|
||||||
lvalue: Lvalue<'tcx>,
|
lvalue: Lvalue,
|
||||||
) -> EvalResult<'tcx, Lvalue<'tcx>> {
|
) -> EvalResult<'tcx, Lvalue> {
|
||||||
let new_lvalue = match lvalue {
|
let new_lvalue = match lvalue {
|
||||||
Lvalue::Local { frame, local } => {
|
Lvalue::Local { frame, local } => {
|
||||||
// -1 since we don't store the return value
|
// -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::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)
|
Ok(new_lvalue)
|
||||||
}
|
}
|
||||||
|
@ -1149,7 +1105,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
|
|
||||||
pub fn write_null(
|
pub fn write_null(
|
||||||
&mut self,
|
&mut self,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx> {
|
) -> EvalResult<'tcx> {
|
||||||
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)
|
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(
|
pub fn write_ptr(
|
||||||
&mut self,
|
&mut self,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
val: Pointer,
|
val: Pointer,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx> {
|
) -> EvalResult<'tcx> {
|
||||||
|
@ -1166,7 +1122,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
|
|
||||||
pub fn write_primval(
|
pub fn write_primval(
|
||||||
&mut self,
|
&mut self,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
val: PrimVal,
|
val: PrimVal,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx> {
|
) -> EvalResult<'tcx> {
|
||||||
|
@ -1176,7 +1132,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
pub fn write_value(
|
pub fn write_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
src_val: Value,
|
src_val: Value,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx> {
|
) -> EvalResult<'tcx> {
|
||||||
//trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty);
|
//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.
|
// correct if we never look at this data with the wrong type.
|
||||||
|
|
||||||
match dest {
|
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 } => {
|
Lvalue::Ptr { ptr, extra, aligned } => {
|
||||||
assert_eq!(extra, LvalueExtra::None);
|
assert_eq!(extra, LvalueExtra::None);
|
||||||
self.write_maybe_aligned_mut(aligned,
|
self.write_maybe_aligned_mut(aligned,
|
||||||
|
@ -1542,7 +1483,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
&mut self,
|
&mut self,
|
||||||
src: Value,
|
src: Value,
|
||||||
src_ty: Ty<'tcx>,
|
src_ty: Ty<'tcx>,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
sty: Ty<'tcx>,
|
sty: Ty<'tcx>,
|
||||||
dty: Ty<'tcx>,
|
dty: Ty<'tcx>,
|
||||||
|
@ -1578,7 +1519,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
&mut self,
|
&mut self,
|
||||||
src: Value,
|
src: Value,
|
||||||
src_ty: Ty<'tcx>,
|
src_ty: Ty<'tcx>,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx> {
|
) -> EvalResult<'tcx> {
|
||||||
match (&src_ty.sty, &dest_ty.sty) {
|
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
|
// Debug output
|
||||||
if let Lvalue::Local { frame, local } = lvalue {
|
if let Lvalue::Local { frame, local } = lvalue {
|
||||||
let mut allocs = Vec::new();
|
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.
|
/// Convenience function to ensure correct usage of 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.
|
|
||||||
pub fn modify_local<F>(
|
pub fn modify_local<F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
frame: usize,
|
frame: usize,
|
||||||
|
|
|
@ -2,7 +2,6 @@ use rustc::mir;
|
||||||
use rustc::ty::layout::{Size, Align};
|
use rustc::ty::layout::{Size, Align};
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use syntax::ast::Mutability;
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
EvalResult,
|
EvalResult,
|
||||||
|
@ -13,7 +12,7 @@ use super::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum Lvalue<'tcx> {
|
pub enum Lvalue {
|
||||||
/// An lvalue referring to a value allocated in the `Memory` system.
|
/// An lvalue referring to a value allocated in the `Memory` system.
|
||||||
Ptr {
|
Ptr {
|
||||||
/// An lvalue may have an invalid (integral or undef) pointer,
|
/// An lvalue may have an invalid (integral or undef) pointer,
|
||||||
|
@ -31,9 +30,6 @@ pub enum Lvalue<'tcx> {
|
||||||
frame: usize,
|
frame: usize,
|
||||||
local: mir::Local,
|
local: mir::Local,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// An lvalue referring to a global
|
|
||||||
Global(GlobalId<'tcx>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -55,19 +51,7 @@ pub struct GlobalId<'tcx> {
|
||||||
pub promoted: Option<mir::Promoted>,
|
pub promoted: Option<mir::Promoted>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
impl<'tcx> Lvalue {
|
||||||
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> {
|
|
||||||
/// Produces an Lvalue that will error if attempted to be read from
|
/// Produces an Lvalue that will error if attempted to be read from
|
||||||
pub fn undef() -> Self {
|
pub fn undef() -> Self {
|
||||||
Self::from_primval_ptr(PrimVal::Undef.into())
|
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> {
|
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
/// Reads a value from the lvalue without going through the intermediate step of obtaining
|
/// Reads a value from the lvalue without going through the intermediate step of obtaining
|
||||||
/// a `miri::Lvalue`
|
/// a `miri::Lvalue`
|
||||||
|
@ -147,7 +111,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
Static(ref static_) => {
|
Static(ref static_) => {
|
||||||
let instance = ty::Instance::mono(self.tcx, static_.def_id);
|
let instance = ty::Instance::mono(self.tcx, static_.def_id);
|
||||||
let cid = GlobalId { instance, promoted: None };
|
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),
|
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)
|
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 {
|
match lvalue {
|
||||||
Lvalue::Ptr { ptr, extra, aligned } => {
|
Lvalue::Ptr { ptr, extra, aligned } => {
|
||||||
assert_eq!(extra, LvalueExtra::None);
|
assert_eq!(extra, LvalueExtra::None);
|
||||||
|
@ -204,13 +168,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
Lvalue::Local { frame, local } => {
|
Lvalue::Local { frame, local } => {
|
||||||
self.stack[frame].get_local(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::*;
|
use rustc::mir::Lvalue::*;
|
||||||
let lvalue = match *mir_lvalue {
|
let lvalue = match *mir_lvalue {
|
||||||
Local(mir::RETURN_POINTER) => self.frame().return_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_) => {
|
Static(ref static_) => {
|
||||||
let instance = ty::Instance::mono(self.tcx, static_.def_id);
|
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) => {
|
Projection(ref proj) => {
|
||||||
|
@ -237,11 +199,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
|
|
||||||
pub fn lvalue_field(
|
pub fn lvalue_field(
|
||||||
&mut self,
|
&mut self,
|
||||||
base: Lvalue<'tcx>,
|
base: Lvalue,
|
||||||
field_index: usize,
|
field_index: usize,
|
||||||
base_ty: Ty<'tcx>,
|
base_ty: Ty<'tcx>,
|
||||||
field_ty: Ty<'tcx>,
|
field_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx, Lvalue<'tcx>> {
|
) -> EvalResult<'tcx, Lvalue> {
|
||||||
let base_layout = self.type_layout(base_ty)?;
|
let base_layout = self.type_layout(base_ty)?;
|
||||||
use rustc::ty::layout::Layout::*;
|
use rustc::ty::layout::Layout::*;
|
||||||
let (offset, packed) = match *base_layout {
|
let (offset, packed) = match *base_layout {
|
||||||
|
@ -312,16 +274,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
Value::ByValPair(..) |
|
Value::ByValPair(..) |
|
||||||
Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
|
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 {
|
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 })
|
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 {
|
Ok(match self.tcx.struct_tail(ty).sty {
|
||||||
ty::TyDynamic(..) => {
|
ty::TyDynamic(..) => {
|
||||||
let (ptr, vtable) = val.into_ptr_vtable_pair(&self.memory)?;
|
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.
|
// 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 = self.force_allocation(base)?;
|
||||||
let (base_ptr, _, aligned) = base.to_ptr_extra_aligned();
|
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(
|
pub(super) fn eval_lvalue_projection(
|
||||||
&mut self,
|
&mut self,
|
||||||
base: Lvalue<'tcx>,
|
base: Lvalue,
|
||||||
base_ty: Ty<'tcx>,
|
base_ty: Ty<'tcx>,
|
||||||
proj_elem: &mir::ProjectionElem<'tcx, mir::Operand<'tcx>, Ty<'tcx>>,
|
proj_elem: &mir::ProjectionElem<'tcx, mir::Operand<'tcx>, Ty<'tcx>>,
|
||||||
) -> EvalResult<'tcx, Lvalue<'tcx>> {
|
) -> EvalResult<'tcx, Lvalue> {
|
||||||
use rustc::mir::ProjectionElem::*;
|
use rustc::mir::ProjectionElem::*;
|
||||||
let (ptr, extra, aligned) = match *proj_elem {
|
let (ptr, extra, aligned) = match *proj_elem {
|
||||||
Field(field, field_ty) => {
|
Field(field, field_ty) => {
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub trait Machine<'tcx>: Sized {
|
||||||
fn eval_fn_call<'a>(
|
fn eval_fn_call<'a>(
|
||||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||||
arg_operands: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
span: Span,
|
span: Span,
|
||||||
sig: ty::FnSig<'tcx>,
|
sig: ty::FnSig<'tcx>,
|
||||||
|
@ -44,7 +44,7 @@ pub trait Machine<'tcx>: Sized {
|
||||||
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
ecx: &mut EvalContext<'a, 'tcx, Self>,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
args: &[mir::Operand<'tcx>],
|
args: &[mir::Operand<'tcx>],
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: ty::Ty<'tcx>,
|
dest_ty: ty::Ty<'tcx>,
|
||||||
dest_layout: &'tcx ty::layout::Layout,
|
dest_layout: &'tcx ty::layout::Layout,
|
||||||
target: mir::BasicBlock,
|
target: mir::BasicBlock,
|
||||||
|
|
|
@ -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.
|
/// The AllocId to assign to the next new regular allocation. Always incremented, never gets smaller.
|
||||||
next_alloc_id: u64,
|
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.
|
/// Number of virtual bytes allocated.
|
||||||
memory_usage: u64,
|
memory_usage: u64,
|
||||||
|
|
||||||
|
@ -280,7 +274,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
||||||
layout,
|
layout,
|
||||||
memory_size: max_memory,
|
memory_size: max_memory,
|
||||||
memory_usage: 0,
|
memory_usage: 0,
|
||||||
static_alloc: HashSet::new(),
|
|
||||||
literal_alloc_cache: HashMap::new(),
|
literal_alloc_cache: HashMap::new(),
|
||||||
reads_are_aligned: Cell::new(true),
|
reads_are_aligned: Cell::new(true),
|
||||||
writes_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
|
/// Reading and writing
|
||||||
impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
|
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
|
/// 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> {
|
pub fn mark_inner_allocation(&mut self, alloc: AllocId, mutability: Mutability) -> EvalResult<'tcx> {
|
||||||
// relocations into other statics are not "inner allocations"
|
// 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)?;
|
self.mark_static_initalized(alloc, mutability)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -38,7 +38,6 @@ pub use self::eval_context::{
|
||||||
pub use self::lvalue::{
|
pub use self::lvalue::{
|
||||||
Lvalue,
|
Lvalue,
|
||||||
LvalueExtra,
|
LvalueExtra,
|
||||||
Global,
|
|
||||||
GlobalId,
|
GlobalId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
op: mir::BinOp,
|
op: mir::BinOp,
|
||||||
left: &mir::Operand<'tcx>,
|
left: &mir::Operand<'tcx>,
|
||||||
right: &mir::Operand<'tcx>,
|
right: &mir::Operand<'tcx>,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx> {
|
) -> EvalResult<'tcx> {
|
||||||
let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
|
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,
|
op: mir::BinOp,
|
||||||
left: &mir::Operand<'tcx>,
|
left: &mir::Operand<'tcx>,
|
||||||
right: &mir::Operand<'tcx>,
|
right: &mir::Operand<'tcx>,
|
||||||
dest: Lvalue<'tcx>,
|
dest: Lvalue,
|
||||||
dest_ty: Ty<'tcx>,
|
dest_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx, bool> {
|
) -> EvalResult<'tcx, bool> {
|
||||||
let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
|
let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
|
||||||
|
|
|
@ -14,9 +14,8 @@ use rustc::ty::subst::Substs;
|
||||||
use super::{
|
use super::{
|
||||||
EvalResult,
|
EvalResult,
|
||||||
EvalContext, StackPopCleanup, TyAndPacked,
|
EvalContext, StackPopCleanup, TyAndPacked,
|
||||||
Global, GlobalId, Lvalue,
|
GlobalId, Lvalue,
|
||||||
Value, PrimVal,
|
HasMemory, Kind,
|
||||||
HasMemory,
|
|
||||||
Machine,
|
Machine,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -179,11 +178,18 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
if self.tcx.has_attr(def_id, "linkage") {
|
if self.tcx.has_attr(def_id, "linkage") {
|
||||||
// FIXME: check that it's `#[linkage = "extern_weak"]`
|
// FIXME: check that it's `#[linkage = "extern_weak"]`
|
||||||
trace!("Initializing an extern global with NULL");
|
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);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
let mir = self.load_mir(instance.def)?;
|
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(
|
let internally_mutable = !mir.return_ty.is_freeze(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
ty::ParamEnv::empty(Reveal::All),
|
ty::ParamEnv::empty(Reveal::All),
|
||||||
|
@ -200,7 +206,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
instance,
|
instance,
|
||||||
span,
|
span,
|
||||||
mir,
|
mir,
|
||||||
Lvalue::Global(cid),
|
Lvalue::from_ptr(ptr),
|
||||||
cleanup,
|
cleanup,
|
||||||
)?;
|
)?;
|
||||||
Ok(true)
|
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];
|
let mir = &self.mir.promoted[index];
|
||||||
self.try(|this| {
|
self.try(|this| {
|
||||||
let ty = this.ecx.monomorphize(mir.return_ty, this.instance.substs);
|
let size = this.ecx.type_size_with_substs(mir.return_ty, this.instance.substs)?.expect("unsized global");
|
||||||
this.ecx.globals.insert(cid, Global::uninitialized(ty));
|
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);
|
trace!("pushing stack frame for {:?}", index);
|
||||||
this.ecx.push_stack_frame(this.instance,
|
this.ecx.push_stack_frame(this.instance,
|
||||||
constant.span,
|
constant.span,
|
||||||
mir,
|
mir,
|
||||||
Lvalue::Global(cid),
|
Lvalue::from_ptr(ptr),
|
||||||
StackPopCleanup::MarkStatic(Mutability::Immutable),
|
StackPopCleanup::MarkStatic(Mutability::Immutable),
|
||||||
)?;
|
)?;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
|
|
|
@ -11,7 +11,7 @@ use interpret::{
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
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);
|
trace!("drop_lvalue: {:#?}", lval);
|
||||||
// We take the address of the object. This may well be unaligned, which is fine for us here.
|
// 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
|
// However, unaligned accesses will probably make the actual drop implementation fail -- a problem shared
|
||||||
|
|
|
@ -204,7 +204,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
fn eval_fn_call(
|
fn eval_fn_call(
|
||||||
&mut self,
|
&mut self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
destination: Option<(Lvalue, mir::BasicBlock)>,
|
||||||
arg_operands: &[mir::Operand<'tcx>],
|
arg_operands: &[mir::Operand<'tcx>],
|
||||||
span: Span,
|
span: Span,
|
||||||
sig: ty::FnSig<'tcx>,
|
sig: ty::FnSig<'tcx>,
|
||||||
|
|
|
@ -16,7 +16,7 @@ use super::{
|
||||||
Machine,
|
Machine,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, Lvalue<'tcx>>;
|
pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, Lvalue>;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum ValidationMode {
|
enum ValidationMode {
|
||||||
|
@ -242,8 +242,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Lvalue::Local { .. } | Lvalue::Global(..) => {
|
Lvalue::Local { .. } => {
|
||||||
// These are not backed by memory, so we have nothing to do.
|
// Not backed by memory, so we have nothing to do.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,12 @@ impl ::std::convert::From<MemoryPointer> 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
|
/// 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
|
/// `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
|
/// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue