Skip to content

Commit 00e524c

Browse files
committed
Move Pointer to its own module
1 parent 99ed98b commit 00e524c

File tree

2 files changed

+155
-147
lines changed

2 files changed

+155
-147
lines changed

Diff for: src/librustc/mir/interpret/mod.rs

+4-147
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ macro_rules! err {
1818
mod error;
1919
mod value;
2020
mod allocation;
21+
mod pointer;
2122

2223
pub use self::error::{
2324
EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstEvalErr, struct_error,
@@ -31,11 +32,13 @@ pub use self::allocation::{
3132
Relocations, UndefMask,
3233
};
3334

35+
pub use self::pointer::{Pointer, PointerArithmetic};
36+
3437
use std::fmt;
3538
use mir;
3639
use hir::def_id::DefId;
3740
use ty::{self, TyCtxt, Instance};
38-
use ty::layout::{self, HasDataLayout, Size};
41+
use ty::layout::{self, Size};
3942
use middle::region;
4043
use std::io;
4144
use std::hash::Hash;
@@ -80,152 +83,6 @@ pub struct GlobalId<'tcx> {
8083
pub promoted: Option<mir::Promoted>,
8184
}
8285

83-
////////////////////////////////////////////////////////////////////////////////
84-
// Pointer arithmetic
85-
////////////////////////////////////////////////////////////////////////////////
86-
87-
pub trait PointerArithmetic: layout::HasDataLayout {
88-
// These are not supposed to be overridden.
89-
90-
#[inline(always)]
91-
fn pointer_size(&self) -> Size {
92-
self.data_layout().pointer_size
93-
}
94-
95-
//// Trunace the given value to the pointer size; also return whether there was an overflow
96-
#[inline]
97-
fn truncate_to_ptr(&self, val: u128) -> (u64, bool) {
98-
let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
99-
((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
100-
}
101-
102-
#[inline]
103-
fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
104-
let (res, over) = self.overflowing_offset(val, i);
105-
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
106-
}
107-
108-
#[inline]
109-
fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
110-
let (res, over1) = val.overflowing_add(i);
111-
let (res, over2) = self.truncate_to_ptr(u128::from(res));
112-
(res, over1 || over2)
113-
}
114-
115-
#[inline]
116-
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
117-
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
118-
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
119-
}
120-
121-
// Overflow checking only works properly on the range from -u64 to +u64.
122-
#[inline]
123-
fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
124-
// FIXME: is it possible to over/underflow here?
125-
if i < 0 {
126-
// trickery to ensure that i64::min_value() works fine
127-
// this formula only works for true negative values, it panics for zero!
128-
let n = u64::max_value() - (i as u64) + 1;
129-
val.overflowing_sub(n)
130-
} else {
131-
self.overflowing_offset(val, i as u64)
132-
}
133-
}
134-
}
135-
136-
impl<T: layout::HasDataLayout> PointerArithmetic for T {}
137-
138-
139-
/// Pointer is generic over the type that represents a reference to Allocations,
140-
/// thus making it possible for the most convenient representation to be used in
141-
/// each context.
142-
///
143-
/// Defaults to the index based and loosely coupled AllocId.
144-
///
145-
/// Pointer is also generic over the `Tag` associated with each pointer,
146-
/// which is used to do provenance tracking during execution.
147-
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
148-
pub struct Pointer<Tag=(),Id=AllocId> {
149-
pub alloc_id: Id,
150-
pub offset: Size,
151-
pub tag: Tag,
152-
}
153-
154-
/// Produces a `Pointer` which points to the beginning of the Allocation
155-
impl From<AllocId> for Pointer {
156-
#[inline(always)]
157-
fn from(alloc_id: AllocId) -> Self {
158-
Pointer::new(alloc_id, Size::ZERO)
159-
}
160-
}
161-
162-
impl<'tcx> Pointer<()> {
163-
#[inline(always)]
164-
pub fn new(alloc_id: AllocId, offset: Size) -> Self {
165-
Pointer { alloc_id, offset, tag: () }
166-
}
167-
168-
#[inline(always)]
169-
pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
170-
where Tag: Default
171-
{
172-
Pointer::new_with_tag(self.alloc_id, self.offset, Default::default())
173-
}
174-
}
175-
176-
impl<'tcx, Tag> Pointer<Tag> {
177-
#[inline(always)]
178-
pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
179-
Pointer { alloc_id, offset, tag }
180-
}
181-
182-
#[inline]
183-
pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
184-
Ok(Pointer::new_with_tag(
185-
self.alloc_id,
186-
Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
187-
self.tag
188-
))
189-
}
190-
191-
#[inline]
192-
pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
193-
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
194-
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
195-
}
196-
197-
#[inline(always)]
198-
pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
199-
self.overflowing_offset(i, cx).0
200-
}
201-
202-
#[inline]
203-
pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
204-
Ok(Pointer::new_with_tag(
205-
self.alloc_id,
206-
Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
207-
self.tag,
208-
))
209-
}
210-
211-
#[inline]
212-
pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
213-
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
214-
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
215-
}
216-
217-
#[inline(always)]
218-
pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
219-
self.overflowing_signed_offset(i128::from(i), cx).0
220-
}
221-
222-
#[inline(always)]
223-
pub fn erase_tag(self) -> Pointer {
224-
Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
225-
}
226-
}
227-
228-
22986
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
23087
pub struct AllocId(pub u64);
23188

Diff for: src/librustc/mir/interpret/pointer.rs

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
use mir;
2+
use ty::layout::{self, HasDataLayout, Size};
3+
4+
use super::{
5+
AllocId, EvalResult,
6+
};
7+
8+
////////////////////////////////////////////////////////////////////////////////
9+
// Pointer arithmetic
10+
////////////////////////////////////////////////////////////////////////////////
11+
12+
pub trait PointerArithmetic: layout::HasDataLayout {
13+
// These are not supposed to be overridden.
14+
15+
#[inline(always)]
16+
fn pointer_size(&self) -> Size {
17+
self.data_layout().pointer_size
18+
}
19+
20+
//// Trunace the given value to the pointer size; also return whether there was an overflow
21+
#[inline]
22+
fn truncate_to_ptr(&self, val: u128) -> (u64, bool) {
23+
let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
24+
((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
25+
}
26+
27+
#[inline]
28+
fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
29+
let (res, over) = self.overflowing_offset(val, i);
30+
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
31+
}
32+
33+
#[inline]
34+
fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) {
35+
let (res, over1) = val.overflowing_add(i);
36+
let (res, over2) = self.truncate_to_ptr(u128::from(res));
37+
(res, over1 || over2)
38+
}
39+
40+
#[inline]
41+
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
42+
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
43+
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
44+
}
45+
46+
// Overflow checking only works properly on the range from -u64 to +u64.
47+
#[inline]
48+
fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
49+
// FIXME: is it possible to over/underflow here?
50+
if i < 0 {
51+
// trickery to ensure that i64::min_value() works fine
52+
// this formula only works for true negative values, it panics for zero!
53+
let n = u64::max_value() - (i as u64) + 1;
54+
val.overflowing_sub(n)
55+
} else {
56+
self.overflowing_offset(val, i as u64)
57+
}
58+
}
59+
}
60+
61+
impl<T: layout::HasDataLayout> PointerArithmetic for T {}
62+
63+
64+
/// Pointer is generic over the type that represents a reference to Allocations,
65+
/// thus making it possible for the most convenient representation to be used in
66+
/// each context.
67+
///
68+
/// Defaults to the index based and loosely coupled AllocId.
69+
///
70+
/// Pointer is also generic over the `Tag` associated with each pointer,
71+
/// which is used to do provenance tracking during execution.
72+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
73+
pub struct Pointer<Tag=(),Id=AllocId> {
74+
pub alloc_id: Id,
75+
pub offset: Size,
76+
pub tag: Tag,
77+
}
78+
79+
/// Produces a `Pointer` which points to the beginning of the Allocation
80+
impl From<AllocId> for Pointer {
81+
#[inline(always)]
82+
fn from(alloc_id: AllocId) -> Self {
83+
Pointer::new(alloc_id, Size::ZERO)
84+
}
85+
}
86+
87+
impl<'tcx> Pointer<()> {
88+
#[inline(always)]
89+
pub fn new(alloc_id: AllocId, offset: Size) -> Self {
90+
Pointer { alloc_id, offset, tag: () }
91+
}
92+
93+
#[inline(always)]
94+
pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
95+
where Tag: Default
96+
{
97+
Pointer::new_with_tag(self.alloc_id, self.offset, Default::default())
98+
}
99+
}
100+
101+
impl<'tcx, Tag> Pointer<Tag> {
102+
#[inline(always)]
103+
pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
104+
Pointer { alloc_id, offset, tag }
105+
}
106+
107+
#[inline]
108+
pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
109+
Ok(Pointer::new_with_tag(
110+
self.alloc_id,
111+
Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
112+
self.tag
113+
))
114+
}
115+
116+
#[inline]
117+
pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) {
118+
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
119+
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
120+
}
121+
122+
#[inline(always)]
123+
pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
124+
self.overflowing_offset(i, cx).0
125+
}
126+
127+
#[inline]
128+
pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> {
129+
Ok(Pointer::new_with_tag(
130+
self.alloc_id,
131+
Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
132+
self.tag,
133+
))
134+
}
135+
136+
#[inline]
137+
pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
138+
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
139+
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
140+
}
141+
142+
#[inline(always)]
143+
pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
144+
self.overflowing_signed_offset(i128::from(i), cx).0
145+
}
146+
147+
#[inline(always)]
148+
pub fn erase_tag(self) -> Pointer {
149+
Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
150+
}
151+
}

0 commit comments

Comments
 (0)