Skip to content

Commit 9ce0803

Browse files
committed
Move Pointer to its own module
1 parent 5c9b456 commit 9ce0803

File tree

2 files changed

+148
-140
lines changed

2 files changed

+148
-140
lines changed

src/librustc/mir/interpret/mod.rs

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

src/librustc/mir/interpret/pointer.rs

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

0 commit comments

Comments
 (0)