add Borrow tag to pointers; remove old locking code
This commit is contained in:
parent
38ed191d28
commit
b84f7e2029
8 changed files with 119 additions and 171 deletions
|
|
@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx, 'mir> {
|
|||
fn emulate_foreign_item(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: PlaceTy<'tcx>,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: PlaceTy<'tcx, Borrow>,
|
||||
ret: mir::BasicBlock,
|
||||
) -> EvalResult<'tcx>;
|
||||
|
||||
|
|
@ -28,28 +28,28 @@ pub trait EvalContextExt<'tcx, 'mir> {
|
|||
fn emulate_missing_fn(
|
||||
&mut self,
|
||||
path: String,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: Option<PlaceTy<'tcx>>,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: Option<PlaceTy<'tcx, Borrow>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
) -> EvalResult<'tcx>;
|
||||
|
||||
fn find_fn(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: Option<PlaceTy<'tcx>>,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: Option<PlaceTy<'tcx, Borrow>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>;
|
||||
|
||||
fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx>;
|
||||
fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>;
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
|
||||
fn find_fn(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: Option<PlaceTy<'tcx>>,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: Option<PlaceTy<'tcx, Borrow>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
|
||||
trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place));
|
||||
|
|
@ -108,8 +108,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
|
|||
fn emulate_foreign_item(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: PlaceTy<'tcx>,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: PlaceTy<'tcx, Borrow>,
|
||||
ret: mir::BasicBlock,
|
||||
) -> EvalResult<'tcx> {
|
||||
let attrs = self.tcx.get_attrs(def_id);
|
||||
|
|
@ -675,8 +675,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
|
|||
fn emulate_missing_fn(
|
||||
&mut self,
|
||||
path: String,
|
||||
_args: &[OpTy<'tcx>],
|
||||
dest: Option<PlaceTy<'tcx>>,
|
||||
_args: &[OpTy<'tcx, Borrow>],
|
||||
dest: Option<PlaceTy<'tcx, Borrow>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
) -> EvalResult<'tcx> {
|
||||
// In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early.
|
||||
|
|
@ -724,7 +724,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx> {
|
||||
fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> {
|
||||
self.write_scalar(Scalar::from_int(0, dest.layout.size), dest)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ pub trait FalibleScalarExt {
|
|||
fn to_bytes(self) -> EvalResult<'static, u128>;
|
||||
}
|
||||
|
||||
impl FalibleScalarExt for Scalar {
|
||||
impl<Tag> FalibleScalarExt for Scalar<Tag> {
|
||||
fn to_bytes(self) -> EvalResult<'static, u128> {
|
||||
match self {
|
||||
Scalar::Bits { bits, size } => {
|
||||
|
|
@ -19,7 +19,7 @@ impl FalibleScalarExt for Scalar {
|
|||
}
|
||||
}
|
||||
|
||||
impl FalibleScalarExt for ScalarMaybeUndef {
|
||||
impl<Tag> FalibleScalarExt for ScalarMaybeUndef<Tag> {
|
||||
fn to_bytes(self) -> EvalResult<'static, u128> {
|
||||
self.not_undef()?.to_bytes()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc::mir::interpret::{EvalResult, PointerArithmetic};
|
|||
use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy};
|
||||
|
||||
use super::{
|
||||
Value, Scalar, ScalarMaybeUndef,
|
||||
Value, Scalar, ScalarMaybeUndef, Borrow,
|
||||
FalibleScalarExt, OperatorEvalContextExt
|
||||
};
|
||||
|
||||
|
|
@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx> {
|
|||
fn call_intrinsic(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: PlaceTy<'tcx>,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: PlaceTy<'tcx, Borrow>,
|
||||
) -> EvalResult<'tcx>;
|
||||
}
|
||||
|
||||
|
|
@ -23,8 +23,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
|||
fn call_intrinsic(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: PlaceTy<'tcx>,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: PlaceTy<'tcx, Borrow>,
|
||||
) -> EvalResult<'tcx> {
|
||||
if self.emulate_intrinsic(instance, args, dest)? {
|
||||
return Ok(());
|
||||
|
|
|
|||
61
src/lib.rs
61
src/lib.rs
|
|
@ -21,11 +21,9 @@ use rustc::ty::layout::{TyLayout, LayoutOf, Size};
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir;
|
||||
|
||||
use syntax::ast::Mutability;
|
||||
use syntax::attr;
|
||||
|
||||
|
||||
pub use rustc::mir::interpret::*;
|
||||
pub use rustc_mir::interpret::*;
|
||||
pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity
|
||||
|
||||
|
|
@ -34,9 +32,9 @@ mod operator;
|
|||
mod intrinsic;
|
||||
mod helpers;
|
||||
mod tls;
|
||||
mod locks;
|
||||
mod range_map;
|
||||
mod mono_hash_map;
|
||||
mod stacked_borrows;
|
||||
|
||||
use fn_call::EvalContextExt as MissingFnsEvalContextExt;
|
||||
use operator::EvalContextExt as OperatorEvalContextExt;
|
||||
|
|
@ -45,6 +43,7 @@ use tls::{EvalContextExt as TlsEvalContextExt, TlsData};
|
|||
use range_map::RangeMap;
|
||||
use helpers::FalibleScalarExt;
|
||||
use mono_hash_map::MonoHashMap;
|
||||
use stacked_borrows::Borrow;
|
||||
|
||||
pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
|
@ -56,7 +55,6 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
|
|||
tcx.at(syntax::source_map::DUMMY_SP),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
Evaluator::new(validate),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
|
||||
|
|
@ -118,9 +116,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
|
|||
let foo = ecx.memory.allocate_static_bytes(b"foo\0");
|
||||
let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8);
|
||||
let foo_layout = ecx.layout_of(foo_ty)?;
|
||||
let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be interned in just a second
|
||||
let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?;
|
||||
ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?;
|
||||
ecx.memory.intern_static(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?;
|
||||
ecx.memory.mark_immutable(foo_place.to_ptr()?.alloc_id)?;
|
||||
ecx.write_scalar(foo_place.ptr, dest)?;
|
||||
|
||||
assert!(args.next().is_none(), "start lang item has more arguments than expected");
|
||||
|
|
@ -227,7 +225,7 @@ impl Into<MemoryKind<MiriMemoryKind>> for MiriMemoryKind {
|
|||
pub struct Evaluator<'tcx> {
|
||||
/// Environment variables set by `setenv`
|
||||
/// Miri does not expose env vars from the host to the emulated program
|
||||
pub(crate) env_vars: HashMap<Vec<u8>, Pointer>,
|
||||
pub(crate) env_vars: HashMap<Vec<u8>, Pointer<Borrow>>,
|
||||
|
||||
/// TLS state
|
||||
pub(crate) tls: TlsData<'tcx>,
|
||||
|
|
@ -247,11 +245,11 @@ impl<'tcx> Evaluator<'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
||||
type MemoryData = ();
|
||||
type MemoryKinds = MiriMemoryKind;
|
||||
type PointerTag = (); // still WIP
|
||||
type AllocExtra = ();
|
||||
type PointerTag = Borrow;
|
||||
|
||||
type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<()>)>;
|
||||
type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<Borrow, Self::AllocExtra>)>;
|
||||
|
||||
const STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::MutStatic);
|
||||
|
||||
|
|
@ -282,8 +280,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
|||
fn find_fn(
|
||||
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: Option<PlaceTy<'tcx>>,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: Option<PlaceTy<'tcx, Borrow>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
|
||||
ecx.find_fn(instance, args, dest, ret)
|
||||
|
|
@ -292,8 +290,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
|||
fn call_intrinsic(
|
||||
ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: PlaceTy<'tcx>,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: PlaceTy<'tcx, Borrow>,
|
||||
) -> EvalResult<'tcx> {
|
||||
ecx.call_intrinsic(instance, args, dest)
|
||||
}
|
||||
|
|
@ -301,17 +299,17 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
|||
fn ptr_op(
|
||||
ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
bin_op: mir::BinOp,
|
||||
left: Scalar,
|
||||
left: Scalar<Borrow>,
|
||||
left_layout: TyLayout<'tcx>,
|
||||
right: Scalar,
|
||||
right: Scalar<Borrow>,
|
||||
right_layout: TyLayout<'tcx>,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||
) -> EvalResult<'tcx, (Scalar<Borrow>, bool)> {
|
||||
ecx.ptr_op(bin_op, left, left_layout, right, right_layout)
|
||||
}
|
||||
|
||||
fn box_alloc(
|
||||
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
dest: PlaceTy<'tcx>,
|
||||
dest: PlaceTy<'tcx, Borrow>,
|
||||
) -> EvalResult<'tcx> {
|
||||
trace!("box_alloc for {:?}", dest.layout.ty);
|
||||
// Call the `exchange_malloc` lang item
|
||||
|
|
@ -351,7 +349,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
|||
fn find_foreign_static(
|
||||
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
|
||||
) -> EvalResult<'tcx, Cow<'tcx, Allocation<Borrow, Self::AllocExtra>>> {
|
||||
let attrs = tcx.get_attrs(def_id);
|
||||
let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
|
||||
Some(name) => name.as_str(),
|
||||
|
|
@ -371,16 +369,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
|||
Ok(Cow::Owned(alloc))
|
||||
}
|
||||
|
||||
fn validation_op(
|
||||
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||
_op: ::rustc::mir::ValidationOp,
|
||||
_operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>,
|
||||
) -> EvalResult<'tcx> {
|
||||
// FIXME: prevent this from ICEing
|
||||
//ecx.validation_op(op, operand)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>
|
||||
{
|
||||
// We are not interested in detecting loops
|
||||
|
|
@ -389,8 +377,19 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
|
|||
|
||||
fn static_with_default_tag(
|
||||
alloc: &'_ Allocation
|
||||
) -> Cow<'_, Allocation<Self::PointerTag>> {
|
||||
let alloc = alloc.clone();
|
||||
) -> Cow<'_, Allocation<Borrow, Self::AllocExtra>> {
|
||||
let alloc: Allocation<Borrow, Self::AllocExtra> = Allocation {
|
||||
bytes: alloc.bytes.clone(),
|
||||
relocations: Relocations::from_presorted(
|
||||
alloc.relocations.iter()
|
||||
.map(|&(offset, ((), alloc))| (offset, (Borrow::default(), alloc)))
|
||||
.collect()
|
||||
),
|
||||
undef_mask: alloc.undef_mask.clone(),
|
||||
align: alloc.align,
|
||||
mutability: alloc.mutability,
|
||||
extra: Self::AllocExtra::default(),
|
||||
};
|
||||
Cow::Owned(alloc)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
94
src/locks.rs
94
src/locks.rs
|
|
@ -1,94 +0,0 @@
|
|||
#![allow(unused)]
|
||||
|
||||
use super::*;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::layout::Size;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Locks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Just some dummy to keep this compiling; I think some of this will be useful later
|
||||
type AbsPlace<'tcx> = ::rustc::ty::Ty<'tcx>;
|
||||
|
||||
/// Information about a lock that is currently held.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct LockInfo<'tcx> {
|
||||
/// Stores for which lifetimes (of the original write lock) we got
|
||||
/// which suspensions.
|
||||
suspended: HashMap<WriteLockId<'tcx>, Vec<region::Scope>>,
|
||||
/// The current state of the lock that's actually effective.
|
||||
pub active: Lock,
|
||||
}
|
||||
|
||||
/// Write locks are identified by a stack frame and an "abstract" (untyped) place.
|
||||
/// It may be tempting to use the lifetime as identifier, but that does not work
|
||||
/// for two reasons:
|
||||
/// * First of all, due to subtyping, the same lock may be referred to with different
|
||||
/// lifetimes.
|
||||
/// * Secondly, different write locks may actually have the same lifetime. See `test2`
|
||||
/// in `run-pass/many_shr_bor.rs`.
|
||||
/// The Id is "captured" when the lock is first suspended; at that point, the borrow checker
|
||||
/// considers the path frozen and hence the Id remains stable.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct WriteLockId<'tcx> {
|
||||
frame: usize,
|
||||
path: AbsPlace<'tcx>,
|
||||
}
|
||||
|
||||
|
||||
use rustc::mir::interpret::Lock::*;
|
||||
use rustc::mir::interpret::Lock;
|
||||
|
||||
impl<'tcx> Default for LockInfo<'tcx> {
|
||||
fn default() -> Self {
|
||||
LockInfo::new(NoLock)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LockInfo<'tcx> {
|
||||
fn new(lock: Lock) -> LockInfo<'tcx> {
|
||||
LockInfo {
|
||||
suspended: HashMap::new(),
|
||||
active: lock,
|
||||
}
|
||||
}
|
||||
|
||||
fn access_permitted(&self, frame: Option<usize>, access: AccessKind) -> bool {
|
||||
use super::AccessKind::*;
|
||||
match (&self.active, access) {
|
||||
(&NoLock, _) => true,
|
||||
(&ReadLock(ref lfts), Read) => {
|
||||
assert!(!lfts.is_empty(), "Someone left an empty read lock behind.");
|
||||
// Read access to read-locked region is okay, no matter who's holding the read lock.
|
||||
true
|
||||
}
|
||||
(&WriteLock(ref lft), _) => {
|
||||
// All access is okay if we are the ones holding it
|
||||
Some(lft.frame) == frame
|
||||
}
|
||||
_ => false, // Nothing else is okay.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RangeMap<LockInfo<'tcx>> {
|
||||
pub fn check(
|
||||
&self,
|
||||
frame: Option<usize>,
|
||||
offset: u64,
|
||||
len: u64,
|
||||
access: AccessKind,
|
||||
) -> Result<(), LockInfo<'tcx>> {
|
||||
if len == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
for lock in self.iter(offset, len) {
|
||||
// Check if the lock is in conflict with the access.
|
||||
if !lock.access_permitted(frame, access) {
|
||||
return Err(lock.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -7,44 +7,44 @@ pub trait EvalContextExt<'tcx> {
|
|||
fn ptr_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: Scalar,
|
||||
left: Scalar<Borrow>,
|
||||
left_layout: TyLayout<'tcx>,
|
||||
right: Scalar,
|
||||
right: Scalar<Borrow>,
|
||||
right_layout: TyLayout<'tcx>,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)>;
|
||||
) -> EvalResult<'tcx, (Scalar<Borrow>, bool)>;
|
||||
|
||||
fn ptr_int_arithmetic(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: Pointer,
|
||||
left: Pointer<Borrow>,
|
||||
right: u128,
|
||||
signed: bool,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)>;
|
||||
) -> EvalResult<'tcx, (Scalar<Borrow>, bool)>;
|
||||
|
||||
fn ptr_eq(
|
||||
&self,
|
||||
left: Scalar,
|
||||
right: Scalar,
|
||||
left: Scalar<Borrow>,
|
||||
right: Scalar<Borrow>,
|
||||
size: Size,
|
||||
) -> EvalResult<'tcx, bool>;
|
||||
|
||||
fn pointer_offset_inbounds(
|
||||
&self,
|
||||
ptr: Scalar,
|
||||
ptr: Scalar<Borrow>,
|
||||
pointee_ty: Ty<'tcx>,
|
||||
offset: i64,
|
||||
) -> EvalResult<'tcx, Scalar>;
|
||||
) -> EvalResult<'tcx, Scalar<Borrow>>;
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
|
||||
fn ptr_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: Scalar,
|
||||
left: Scalar<Borrow>,
|
||||
left_layout: TyLayout<'tcx>,
|
||||
right: Scalar,
|
||||
right: Scalar<Borrow>,
|
||||
right_layout: TyLayout<'tcx>,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||
) -> EvalResult<'tcx, (Scalar<Borrow>, bool)> {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right);
|
||||
|
|
@ -124,8 +124,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
|||
|
||||
fn ptr_eq(
|
||||
&self,
|
||||
left: Scalar,
|
||||
right: Scalar,
|
||||
left: Scalar<Borrow>,
|
||||
right: Scalar<Borrow>,
|
||||
size: Size,
|
||||
) -> EvalResult<'tcx, bool> {
|
||||
Ok(match (left, right) {
|
||||
|
|
@ -203,13 +203,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
|||
fn ptr_int_arithmetic(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: Pointer,
|
||||
left: Pointer<Borrow>,
|
||||
right: u128,
|
||||
signed: bool,
|
||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||
) -> EvalResult<'tcx, (Scalar<Borrow>, bool)> {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) {
|
||||
fn map_to_primval((res, over): (Pointer<Borrow>, bool)) -> (Scalar<Borrow>, bool) {
|
||||
(Scalar::Ptr(res), over)
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +237,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
|||
if right & base_mask == base_mask {
|
||||
// Case 1: The base address bits are all preserved, i.e., right is all-1 there
|
||||
let offset = (left.offset.bytes() as u128 & right) as u64;
|
||||
(Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(offset))), false)
|
||||
(
|
||||
Scalar::Ptr(Pointer::new_with_tag(
|
||||
left.alloc_id,
|
||||
Size::from_bytes(offset),
|
||||
left.tag,
|
||||
)),
|
||||
false,
|
||||
)
|
||||
} else if right & base_mask == 0 {
|
||||
// Case 2: The base address bits are all taken away, i.e., right is all-0 there
|
||||
(Scalar::Bits { bits: (left.offset.bytes() as u128) & right, size: ptr_size }, false)
|
||||
|
|
@ -277,10 +284,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
|||
/// allocation.
|
||||
fn pointer_offset_inbounds(
|
||||
&self,
|
||||
ptr: Scalar,
|
||||
ptr: Scalar<Borrow>,
|
||||
pointee_ty: Ty<'tcx>,
|
||||
offset: i64,
|
||||
) -> EvalResult<'tcx, Scalar> {
|
||||
) -> EvalResult<'tcx, Scalar<Borrow>> {
|
||||
// FIXME: assuming here that type size is < i64::max_value()
|
||||
let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
|
||||
let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?;
|
||||
|
|
|
|||
36
src/stacked_borrows.rs
Normal file
36
src/stacked_borrows.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use super::RangeMap;
|
||||
|
||||
pub type Timestamp = u64;
|
||||
|
||||
/// Information about a potentially mutable borrow
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum Mut {
|
||||
/// A unique, mutable reference
|
||||
Uniq(Timestamp),
|
||||
/// Any raw pointer, or a shared borrow with interior mutability
|
||||
Raw,
|
||||
}
|
||||
|
||||
/// Information about any kind of borrow
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum Borrow {
|
||||
/// A mutable borrow, a raw pointer, or a shared borrow with interior mutability
|
||||
Mut(Mut),
|
||||
/// A shared borrow without interior mutability
|
||||
Frz(Timestamp)
|
||||
}
|
||||
|
||||
/// An item in the borrow stack
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum BorStackItem {
|
||||
/// Defines which references are permitted to mutate *if* the location is not frozen
|
||||
Mut(Mut),
|
||||
/// A barrier, tracking the function it belongs to by its index on the call stack
|
||||
FnBarrier(usize)
|
||||
}
|
||||
|
||||
impl Default for Borrow {
|
||||
fn default() -> Self {
|
||||
Borrow::Mut(Mut::Raw)
|
||||
}
|
||||
}
|
||||
10
src/tls.rs
10
src/tls.rs
|
|
@ -5,14 +5,14 @@ use rustc::{ty, ty::layout::HasDataLayout, mir};
|
|||
|
||||
use super::{
|
||||
EvalResult, EvalErrorKind, StackPopCleanup, EvalContext, Evaluator,
|
||||
MPlaceTy, Scalar,
|
||||
MPlaceTy, Scalar, Borrow,
|
||||
};
|
||||
|
||||
pub type TlsKey = u128;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct TlsEntry<'tcx> {
|
||||
pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread.
|
||||
pub(crate) data: Scalar<Borrow>, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread.
|
||||
pub(crate) dtor: Option<ty::Instance<'tcx>>,
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ impl<'tcx> TlsData<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> {
|
||||
pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar<Borrow>> {
|
||||
match self.keys.get(&key) {
|
||||
Some(&TlsEntry { data, .. }) => {
|
||||
trace!("TLS key {} loaded: {:?}", key, data);
|
||||
|
|
@ -77,7 +77,7 @@ impl<'tcx> TlsData<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> {
|
||||
pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar<Borrow>) -> EvalResult<'tcx> {
|
||||
match self.keys.get_mut(&key) {
|
||||
Some(&mut TlsEntry { ref mut data, .. }) => {
|
||||
trace!("TLS key {} stored: {:?}", key, new_data);
|
||||
|
|
@ -110,7 +110,7 @@ impl<'tcx> TlsData<'tcx> {
|
|||
&mut self,
|
||||
key: Option<TlsKey>,
|
||||
cx: impl HasDataLayout,
|
||||
) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> {
|
||||
) -> Option<(ty::Instance<'tcx>, Scalar<Borrow>, TlsKey)> {
|
||||
use std::collections::Bound::*;
|
||||
|
||||
let thread_local = &mut self.keys;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue