without all those copies of constants, we can finally make eval_operand take &self
This commit is contained in:
parent
c141ccf158
commit
2592b20347
4 changed files with 53 additions and 59 deletions
|
|
@ -427,12 +427,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
// avoid allocations. If you already know the layout, you can pass it in
|
||||
// to avoid looking it up again.
|
||||
fn eval_place_to_op(
|
||||
&mut self,
|
||||
&self,
|
||||
mir_place: &mir::Place<'tcx>,
|
||||
layout: Option<TyLayout<'tcx>>,
|
||||
) -> EvalResult<'tcx, OpTy<'tcx>> {
|
||||
use rustc::mir::Place::*;
|
||||
Ok(match *mir_place {
|
||||
let op = match *mir_place {
|
||||
Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
|
||||
Local(local) => {
|
||||
let op = *self.frame().locals[local].access()?;
|
||||
|
|
@ -446,21 +446,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
self.operand_projection(op, &proj.elem)?
|
||||
}
|
||||
|
||||
// Everything else is an mplace, so we just call `eval_place`.
|
||||
// Note that getting an mplace for a static aways requires `&mut`,
|
||||
// so this does not "cost" us anything in terms if mutability.
|
||||
Promoted(_) | Static(_) => {
|
||||
let place = self.eval_place(mir_place)?;
|
||||
place.to_mem_place().into()
|
||||
}
|
||||
})
|
||||
_ => self.eval_place_to_mplace(mir_place)?.into(),
|
||||
};
|
||||
|
||||
trace!("eval_place_to_op: got {:?}", *op);
|
||||
Ok(op)
|
||||
}
|
||||
|
||||
/// Evaluate the operand, returning a place where you can then find the data.
|
||||
/// if you already know the layout, you can save two some table lookups
|
||||
/// by passing it in here.
|
||||
pub fn eval_operand(
|
||||
&mut self,
|
||||
&self,
|
||||
mir_op: &mir::Operand<'tcx>,
|
||||
layout: Option<TyLayout<'tcx>>,
|
||||
) -> EvalResult<'tcx, OpTy<'tcx>> {
|
||||
|
|
@ -486,7 +483,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
|
||||
/// Evaluate a bunch of operands at once
|
||||
pub(crate) fn eval_operands(
|
||||
&mut self,
|
||||
&self,
|
||||
ops: &[mir::Operand<'tcx>],
|
||||
) -> EvalResult<'tcx, Vec<OpTy<'tcx>>> {
|
||||
ops.into_iter()
|
||||
|
|
@ -495,8 +492,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
// Also used e.g. when miri runs into a constant.
|
||||
// Unfortunately, this needs an `&mut` to be able to allocate a copy of a `ByRef`
|
||||
// constant. This bleeds up to `eval_operand` needing `&mut`.
|
||||
pub fn const_value_to_op(
|
||||
&self,
|
||||
val: ConstValue<'tcx>,
|
||||
|
|
@ -527,18 +522,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
self.const_value_to_op(cv.val)
|
||||
}
|
||||
|
||||
/// We cannot do self.read_value(self.eval_operand) due to eval_operand taking &mut self,
|
||||
/// so this helps avoid unnecessary let.
|
||||
#[inline]
|
||||
pub fn eval_operand_and_read_value(
|
||||
&mut self,
|
||||
op: &mir::Operand<'tcx>,
|
||||
layout: Option<TyLayout<'tcx>>,
|
||||
) -> EvalResult<'tcx, ValTy<'tcx>> {
|
||||
let op = self.eval_operand(op, layout)?;
|
||||
self.read_value(op)
|
||||
}
|
||||
|
||||
/// reads a tag and produces the corresponding variant index
|
||||
pub fn read_discriminant_as_variant_index(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -494,33 +494,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Compute a place. You should only use this if you intend to write into this
|
||||
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
|
||||
pub fn eval_place(&mut self, mir_place: &mir::Place<'tcx>) -> EvalResult<'tcx, PlaceTy<'tcx>> {
|
||||
/// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
|
||||
/// `eval_place` and `eval_place_to_op`.
|
||||
pub(super) fn eval_place_to_mplace(
|
||||
&self,
|
||||
mir_place: &mir::Place<'tcx>
|
||||
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
|
||||
use rustc::mir::Place::*;
|
||||
let place = match *mir_place {
|
||||
Local(mir::RETURN_PLACE) => PlaceTy {
|
||||
place: self.frame().return_place,
|
||||
layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
|
||||
},
|
||||
Local(local) => PlaceTy {
|
||||
place: Place::Local {
|
||||
frame: self.cur_frame(),
|
||||
local,
|
||||
},
|
||||
layout: self.layout_of_local(self.cur_frame(), local)?,
|
||||
},
|
||||
|
||||
Ok(match *mir_place {
|
||||
Promoted(ref promoted) => {
|
||||
let instance = self.frame().instance;
|
||||
let op = self.global_to_op(GlobalId {
|
||||
instance,
|
||||
promoted: Some(promoted.0),
|
||||
})?;
|
||||
let mplace = op.to_mem_place();
|
||||
let mplace = op.to_mem_place(); // these are always in memory
|
||||
let ty = self.monomorphize(promoted.1, self.substs());
|
||||
PlaceTy {
|
||||
place: Place::Ptr(mplace),
|
||||
MPlaceTy {
|
||||
mplace,
|
||||
layout: self.layout_of(ty)?,
|
||||
}
|
||||
}
|
||||
|
|
@ -539,17 +530,39 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
// global table but not in its local memory.
|
||||
let alloc = self.tcx.alloc_map.lock()
|
||||
.intern_static(cid.instance.def_id());
|
||||
MPlaceTy::from_aligned_ptr(alloc.into(), layout).into()
|
||||
MPlaceTy::from_aligned_ptr(alloc.into(), layout)
|
||||
}
|
||||
|
||||
_ => bug!("eval_place_to_mplace called on {:?}", mir_place),
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute a place. You should only use this if you intend to write into this
|
||||
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
|
||||
pub fn eval_place(&mut self, mir_place: &mir::Place<'tcx>) -> EvalResult<'tcx, PlaceTy<'tcx>> {
|
||||
use rustc::mir::Place::*;
|
||||
let place = match *mir_place {
|
||||
Local(mir::RETURN_PLACE) => PlaceTy {
|
||||
place: self.frame().return_place,
|
||||
layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
|
||||
},
|
||||
Local(local) => PlaceTy {
|
||||
place: Place::Local {
|
||||
frame: self.cur_frame(),
|
||||
local,
|
||||
},
|
||||
layout: self.layout_of_local(self.cur_frame(), local)?,
|
||||
},
|
||||
|
||||
Projection(ref proj) => {
|
||||
let place = self.eval_place(&proj.base)?;
|
||||
self.place_projection(place, &proj.elem)?
|
||||
}
|
||||
|
||||
_ => self.eval_place_to_mplace(mir_place)?.into(),
|
||||
};
|
||||
|
||||
self.dump_place(place.place);
|
||||
|
||||
Ok(place)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -188,9 +188,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
|
||||
BinaryOp(bin_op, ref left, ref right) => {
|
||||
let layout = if binop_left_homogeneous(bin_op) { Some(dest.layout) } else { None };
|
||||
let left = self.eval_operand_and_read_value(left, layout)?;
|
||||
let left = self.read_value(self.eval_operand(left, layout)?)?;
|
||||
let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
|
||||
let right = self.eval_operand_and_read_value(right, layout)?;
|
||||
let right = self.read_value(self.eval_operand(right, layout)?)?;
|
||||
self.binop_ignore_overflow(
|
||||
bin_op,
|
||||
left,
|
||||
|
|
@ -201,9 +201,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
|
||||
CheckedBinaryOp(bin_op, ref left, ref right) => {
|
||||
// Due to the extra boolean in the result, we can never reuse the `dest.layout`.
|
||||
let left = self.eval_operand_and_read_value(left, None)?;
|
||||
let left = self.read_value(self.eval_operand(left, None)?)?;
|
||||
let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
|
||||
let right = self.eval_operand_and_read_value(right, layout)?;
|
||||
let right = self.read_value(self.eval_operand(right, layout)?)?;
|
||||
self.binop_with_overflow(
|
||||
bin_op,
|
||||
left,
|
||||
|
|
@ -214,7 +214,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
|
||||
UnaryOp(un_op, ref operand) => {
|
||||
// The operand always has the same type as the result.
|
||||
let val = self.eval_operand_and_read_value(operand, Some(dest.layout))?;
|
||||
let val = self.read_value(self.eval_operand(operand, Some(dest.layout))?)?;
|
||||
let val = self.unary_op(un_op, val.to_scalar()?, dest.layout)?;
|
||||
self.write_scalar(val, dest)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,8 +52,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
ref targets,
|
||||
..
|
||||
} => {
|
||||
let discr_val = self.eval_operand(discr, None)?;
|
||||
let discr = self.read_value(discr_val)?;
|
||||
let discr = self.read_value(self.eval_operand(discr, None)?)?;
|
||||
trace!("SwitchInt({:?})", *discr);
|
||||
|
||||
// Branch to the `otherwise` case by default, if no match is found.
|
||||
|
|
@ -164,19 +163,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
target,
|
||||
..
|
||||
} => {
|
||||
let cond_val = self.eval_operand_and_read_value(cond, None)?
|
||||
.to_scalar()?
|
||||
.to_bool()?;
|
||||
let cond_val = self.read_value(self.eval_operand(cond, None)?)?
|
||||
.to_scalar()?.to_bool()?;
|
||||
if expected == cond_val {
|
||||
self.goto_block(Some(target))?;
|
||||
} else {
|
||||
use rustc::mir::interpret::EvalErrorKind::*;
|
||||
return match *msg {
|
||||
BoundsCheck { ref len, ref index } => {
|
||||
let len = self.eval_operand_and_read_value(len, None)
|
||||
let len = self.read_value(self.eval_operand(len, None)?)
|
||||
.expect("can't eval len").to_scalar()?
|
||||
.to_bits(self.memory().pointer_size())? as u64;
|
||||
let index = self.eval_operand_and_read_value(index, None)
|
||||
let index = self.read_value(self.eval_operand(index, None)?)
|
||||
.expect("can't eval index").to_scalar()?
|
||||
.to_bits(self.memory().pointer_size())? as u64;
|
||||
err!(BoundsCheck { len, index })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue