Skip to content

Commit cbe8c71

Browse files
committed
Simplify ConstValue
1 parent 72f3af2 commit cbe8c71

File tree

22 files changed

+516
-402
lines changed

22 files changed

+516
-402
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -375,13 +375,6 @@ for ::mir::interpret::ConstValue<'gcx> {
375375
def_id.hash_stable(hcx, hasher);
376376
substs.hash_stable(hcx, hasher);
377377
}
378-
Scalar(val) => {
379-
val.hash_stable(hcx, hasher);
380-
}
381-
ScalarPair(a, b) => {
382-
a.hash_stable(hcx, hasher);
383-
b.hash_stable(hcx, hasher);
384-
}
385378
ByRef(id, alloc, offset) => {
386379
id.hash_stable(hcx, hasher);
387380
alloc.hash_stable(hcx, hasher);
@@ -512,7 +505,7 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
512505
hasher: &mut StableHasher<W>) {
513506
use mir::interpret::EvalErrorKind::*;
514507

515-
mem::discriminant(&self).hash_stable(hcx, hasher);
508+
mem::discriminant(self).hash_stable(hcx, hasher);
516509

517510
match *self {
518511
FunctionArgCountMismatch |
@@ -577,11 +570,11 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
577570
NoMirFor(ref s) => s.hash_stable(hcx, hasher),
578571
UnterminatedCString(ptr) => ptr.hash_stable(hcx, hasher),
579572
PointerOutOfBounds {
580-
ptr,
573+
offset,
581574
access,
582575
allocation_size,
583576
} => {
584-
ptr.hash_stable(hcx, hasher);
577+
offset.hash_stable(hcx, hasher);
585578
access.hash_stable(hcx, hasher);
586579
allocation_size.hash_stable(hcx, hasher)
587580
},

src/librustc/mir/interpret/error.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ pub enum EvalErrorKind<'tcx, O> {
197197
InvalidBool,
198198
InvalidDiscriminant(u128),
199199
PointerOutOfBounds {
200-
ptr: Pointer,
200+
offset: Size,
201201
access: bool,
202202
allocation_size: Size,
203203
},
@@ -440,10 +440,10 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
440440
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441441
use self::EvalErrorKind::*;
442442
match *self {
443-
PointerOutOfBounds { ptr, access, allocation_size } => {
444-
write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}",
443+
PointerOutOfBounds { offset, access, allocation_size } => {
444+
write!(f, "{} at offset {}, outside bounds of allocation with size {}",
445445
if access { "memory access" } else { "pointer computed" },
446-
ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
446+
offset.bytes(), allocation_size.bytes())
447447
},
448448
MemoryLockViolation { ptr, len, frame, access, ref lock } => {
449449
write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}",

src/librustc/mir/interpret/mod.rs

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub use self::value::{Scalar, ConstValue};
2828
use std::fmt;
2929
use mir;
3030
use hir::def_id::DefId;
31-
use ty::{self, TyCtxt, Instance};
31+
use ty::{self, TyCtxt, Instance, Ty, ParamEnvAnd};
3232
use ty::layout::{self, Align, HasDataLayout, Size};
3333
use middle::region;
3434
use std::iter;
@@ -545,7 +545,7 @@ pub struct Allocation<Tag=(),Extra=()> {
545545
pub extra: Extra,
546546
}
547547

548-
impl<Tag, Extra: Default> Allocation<Tag, Extra> {
548+
impl<Tag: Copy, Extra: Default> Allocation<Tag, Extra> {
549549
/// Creates a read-only allocation initialized by the given bytes
550550
pub fn from_bytes(slice: &[u8], align: Align) -> Self {
551551
let mut undef_mask = UndefMask::new(Size::ZERO);
@@ -575,6 +575,144 @@ impl<Tag, Extra: Default> Allocation<Tag, Extra> {
575575
extra: Extra::default(),
576576
}
577577
}
578+
579+
#[inline]
580+
pub fn size(&self) -> Size {
581+
Size::from_bytes(self.bytes.len() as u64)
582+
}
583+
584+
pub fn check_align(
585+
&self,
586+
offset: Size,
587+
required_align: Align,
588+
) -> EvalResult<'tcx> {
589+
if self.align.abi() > required_align.abi() {
590+
return err!(AlignmentCheckFailed {
591+
has: self.align,
592+
required: required_align,
593+
});
594+
}
595+
let offset = offset.bytes();
596+
if offset % required_align.abi() == 0 {
597+
Ok(())
598+
} else {
599+
let has = offset % required_align.abi();
600+
err!(AlignmentCheckFailed {
601+
has: Align::from_bytes(has, has).unwrap(),
602+
required: required_align,
603+
})
604+
}
605+
}
606+
607+
pub fn check_bounds(
608+
&self,
609+
offset: Size,
610+
size: Size,
611+
access: bool,
612+
) -> EvalResult<'tcx> {
613+
let end = offset + size;
614+
let allocation_size = self.size();
615+
if end > allocation_size {
616+
err!(PointerOutOfBounds { offset, access, allocation_size })
617+
} else {
618+
Ok(())
619+
}
620+
}
621+
622+
pub fn check_defined(
623+
&self,
624+
offset: Size,
625+
size: Size,
626+
) -> EvalResult<'tcx> {
627+
self.undef_mask.is_range_defined(
628+
offset,
629+
offset + size,
630+
).or_else(|idx| err!(ReadUndefBytes(idx)))
631+
}
632+
633+
pub fn check_relocations(
634+
&self,
635+
hdl: impl HasDataLayout,
636+
offset: Size,
637+
size: Size,
638+
) -> EvalResult<'tcx> {
639+
if self.relocations(hdl, offset, size)?.len() != 0 {
640+
err!(ReadPointerAsBytes)
641+
} else {
642+
Ok(())
643+
}
644+
}
645+
646+
pub fn relocations(
647+
&self,
648+
hdl: impl HasDataLayout,
649+
offset: Size,
650+
size: Size,
651+
) -> EvalResult<'tcx, &[(Size, (Tag, AllocId))]> {
652+
// We have to go back `pointer_size - 1` bytes, as that one would still overlap with
653+
// the beginning of this range.
654+
let start = offset.bytes().saturating_sub(hdl.pointer_size().bytes() - 1);
655+
let end = offset + size; // this does overflow checking
656+
Ok(self.relocations.range(Size::from_bytes(start)..end))
657+
}
658+
659+
pub fn get_bytes(
660+
&self,
661+
hdl: impl HasDataLayout,
662+
offset: Size,
663+
size: Size,
664+
required_align: Align,
665+
) -> EvalResult<'tcx, &[u8]> {
666+
self.check_align(offset, required_align)?;
667+
self.check_bounds(offset, size, true)?;
668+
self.check_defined(offset, size)?;
669+
self.check_relocations(hdl, offset, size)?;
670+
Ok(self.bytes_ignoring_relocations_and_undef(offset, size))
671+
}
672+
673+
pub fn read_bits(
674+
&self,
675+
tcx: TyCtxt<'_, '_, 'tcx>,
676+
offset: Size,
677+
ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
678+
) -> EvalResult<'tcx, u128> {
679+
let ty = tcx.lift_to_global(&ty).unwrap();
680+
let layout = tcx.layout_of(ty).unwrap_or_else(|e| {
681+
panic!("could not compute layout for {:?}: {:?}", ty, e)
682+
});
683+
let bytes = self.get_bytes(tcx, offset, layout.size, layout.align)?;
684+
Ok(read_target_uint(tcx.data_layout.endian, bytes).unwrap())
685+
}
686+
687+
pub fn read_scalar(
688+
&self,
689+
hdl: impl HasDataLayout,
690+
offset: Size,
691+
) -> EvalResult<'tcx, Scalar<Tag>> {
692+
let size = hdl.data_layout().pointer_size;
693+
let required_align = hdl.data_layout().pointer_align;
694+
self.check_align(offset, required_align)?;
695+
self.check_bounds(offset, size, true)?;
696+
self.check_defined(offset, size)?;
697+
let bytes = self.bytes_ignoring_relocations_and_undef(offset, size);
698+
let offset = read_target_uint(hdl.data_layout().endian, &bytes).unwrap();
699+
let offset = Size::from_bytes(offset as u64);
700+
if let Some(&(tag, alloc_id)) = self.relocations.get(&offset) {
701+
Ok(Pointer::new_with_tag(alloc_id, offset, tag).into())
702+
} else {
703+
Ok(Scalar::Bits {
704+
bits: offset.bytes() as u128,
705+
size: size.bytes() as u8,
706+
})
707+
}
708+
}
709+
710+
fn bytes_ignoring_relocations_and_undef(&self, offset: Size, size: Size) -> &[u8] {
711+
let end = offset + size;
712+
let offset = offset.bytes() as usize;
713+
let end = end.bytes() as usize;
714+
&self.bytes[offset..end]
715+
}
578716
}
579717

580718
impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}

src/librustc/mir/interpret/value.rs

Lines changed: 102 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010

1111
#![allow(unknown_lints)]
1212

13-
use ty::layout::{HasDataLayout, Size};
13+
use ty::layout::{HasDataLayout, Align, Size, TyLayout};
1414
use ty::subst::Substs;
15+
use ty;
1516
use hir::def_id::DefId;
1617

1718
use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
@@ -25,57 +26,130 @@ pub enum ConstValue<'tcx> {
2526
/// evaluation
2627
Unevaluated(DefId, &'tcx Substs<'tcx>),
2728

28-
/// Used only for types with layout::abi::Scalar ABI and ZSTs
29-
///
30-
/// Not using the enum `Value` to encode that this must not be `Undef`
31-
Scalar(Scalar),
32-
33-
/// Used only for *fat pointers* with layout::abi::ScalarPair
34-
///
35-
/// Needed for pattern matching code related to slices and strings.
36-
ScalarPair(Scalar, Scalar),
37-
3829
/// An allocation + offset into the allocation.
3930
/// Invariant: The AllocId matches the allocation.
4031
ByRef(AllocId, &'tcx Allocation, Size),
4132
}
4233

4334
impl<'tcx> ConstValue<'tcx> {
4435
#[inline]
45-
pub fn try_to_scalar(&self) -> Option<Scalar> {
46-
match *self {
47-
ConstValue::Unevaluated(..) |
48-
ConstValue::ByRef(..) |
49-
ConstValue::ScalarPair(..) => None,
50-
ConstValue::Scalar(val) => Some(val),
36+
pub fn try_as_by_ref(&self) -> Option<(AllocId, &'tcx Allocation, Size)> {
37+
match self {
38+
ConstValue::Unevaluated(..) => None,
39+
ConstValue::ByRef(a, b, c) => Some((*a, *b, *c)),
5140
}
5241
}
5342

5443
#[inline]
55-
pub fn try_to_bits(&self, size: Size) -> Option<u128> {
56-
self.try_to_scalar()?.to_bits(size).ok()
44+
/// if this is ByRef, return the same thing but with the offset increased by `n`
45+
pub fn try_offset(&self, n: Size) -> Option<Self> {
46+
let (id, alloc, offset) = self.try_as_by_ref()?;
47+
Some(ConstValue::ByRef(id, alloc, offset + n))
48+
}
49+
50+
#[inline]
51+
pub fn try_get_bytes(&self, hdl: impl HasDataLayout, n: Size, align: Align) -> Option<&[u8]> {
52+
let (_, alloc, offset) = self.try_as_by_ref()?;
53+
alloc.get_bytes(hdl, offset, n, align).ok()
54+
}
55+
56+
#[inline]
57+
pub fn try_to_bits(&self, hdl: impl HasDataLayout, layout: TyLayout<'tcx>) -> Option<u128> {
58+
let bytes = self.try_get_bytes(hdl, layout.size, layout.align)?;
59+
let endian = hdl.data_layout().endian;
60+
super::read_target_uint(endian, &bytes).ok()
5761
}
5862

5963
#[inline]
60-
pub fn try_to_ptr(&self) -> Option<Pointer> {
61-
self.try_to_scalar()?.to_ptr().ok()
64+
pub fn try_to_usize(&self, hdl: impl HasDataLayout) -> Option<u128> {
65+
let size = hdl.data_layout().pointer_size;
66+
let align = hdl.data_layout().pointer_align;
67+
let bytes = self.try_get_bytes(hdl, size, align)?;
68+
let endian = hdl.data_layout().endian;
69+
super::read_target_uint(endian, &bytes).ok()
70+
}
71+
72+
#[inline]
73+
pub fn try_to_ptr(
74+
&self,
75+
hdl: impl HasDataLayout,
76+
) -> Option<Pointer> {
77+
let (_, alloc, offset) = self.try_as_by_ref()?;
78+
alloc.read_scalar(hdl, offset).ok()?.to_ptr().ok()
79+
}
80+
81+
/// e.g. for vtables, fat pointers or single pointers
82+
#[inline]
83+
pub fn new_pointer_list(
84+
list: &[Scalar],
85+
tcx: ty::TyCtxt<'_, '_, 'tcx>,
86+
) -> Self {
87+
let ps = tcx.data_layout().pointer_size;
88+
let mut alloc = Allocation::undef(
89+
ps * list.len() as u64,
90+
tcx.data_layout().pointer_align,
91+
);
92+
alloc.undef_mask.set_range_inbounds(Size::ZERO, ps * list.len() as u64, true);
93+
for (i, s) in list.iter().enumerate() {
94+
let (int, ptr) = match s {
95+
Scalar::Bits { bits, size } => {
96+
assert!(*size as u64 == ps.bytes());
97+
(*bits as u64, None)
98+
}
99+
Scalar::Ptr(ptr) => (ptr.offset.bytes(), Some(ptr)),
100+
};
101+
let i = i * ps.bytes() as usize;
102+
let j = i + ps.bytes() as usize;
103+
super::write_target_uint(
104+
tcx.data_layout().endian,
105+
&mut alloc.bytes[i..j],
106+
int.into(),
107+
).unwrap();
108+
if let Some(ptr) = ptr {
109+
alloc.relocations.insert(
110+
ps * i as u64,
111+
(ptr.tag, ptr.alloc_id),
112+
);
113+
}
114+
}
115+
Self::from_allocation(tcx, alloc)
116+
}
117+
118+
#[inline]
119+
pub fn from_allocation(
120+
tcx: ty::TyCtxt<'_, '_, 'tcx>,
121+
alloc: Allocation,
122+
) -> Self {
123+
let alloc = tcx.intern_const_alloc(alloc);
124+
let alloc_id = tcx.alloc_map.lock().allocate(alloc);
125+
ConstValue::ByRef(alloc_id, alloc, Size::ZERO)
62126
}
63127

64128
#[inline]
65129
pub fn new_slice(
66130
val: Scalar,
67131
len: u64,
68-
cx: impl HasDataLayout
132+
tcx: ty::TyCtxt<'_, '_, 'tcx>,
69133
) -> Self {
70-
ConstValue::ScalarPair(val, Scalar::Bits {
71-
bits: len as u128,
72-
size: cx.data_layout().pointer_size.bytes() as u8,
73-
})
134+
Self::new_pointer_list(
135+
&[
136+
val,
137+
Scalar::Bits {
138+
bits: len as u128,
139+
size: tcx.data_layout.pointer_size.bytes() as u8,
140+
},
141+
],
142+
tcx,
143+
)
74144
}
75145

76146
#[inline]
77-
pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
78-
ConstValue::ScalarPair(val, Scalar::Ptr(vtable))
147+
pub fn new_dyn_trait(
148+
val: Scalar,
149+
vtable: Pointer,
150+
tcx: ty::TyCtxt<'_, '_, 'tcx>,
151+
) -> Self {
152+
Self::new_pointer_list(&[val, vtable.into()], tcx)
79153
}
80154
}
81155

0 commit comments

Comments
 (0)