9
9
// except according to those terms.
10
10
11
11
use std:: fmt:: Write ;
12
- use std:: hash:: { Hash , Hasher } ;
13
12
use std:: mem;
14
13
15
14
use rustc:: hir:: def_id:: DefId ;
16
15
use rustc:: hir:: def:: Def ;
17
16
use rustc:: hir:: map:: definitions:: DefPathData ;
17
+ use rustc:: ich:: StableHashingContext ;
18
18
use rustc:: mir;
19
19
use rustc:: ty:: layout:: {
20
20
self , Size , Align , HasDataLayout , LayoutOf , TyLayout
21
21
} ;
22
22
use rustc:: ty:: subst:: { Subst , Substs } ;
23
23
use rustc:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
24
24
use rustc:: ty:: query:: TyCtxtAt ;
25
- use rustc_data_structures:: fx:: { FxHashSet , FxHasher } ;
26
25
use rustc_data_structures:: indexed_vec:: IndexVec ;
26
+ use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher , StableHasherResult } ;
27
27
use rustc:: mir:: interpret:: {
28
- GlobalId , Scalar , FrameInfo ,
28
+ GlobalId , Scalar , FrameInfo , AllocId ,
29
29
EvalResult , EvalErrorKind ,
30
30
ScalarMaybeUndef ,
31
31
truncate, sign_extend,
@@ -38,6 +38,8 @@ use super::{
38
38
Memory , Machine
39
39
} ;
40
40
41
+ use super :: snapshot:: InfiniteLoopDetector ;
42
+
41
43
pub struct EvalContext < ' a , ' mir , ' tcx : ' a + ' mir , M : Machine < ' mir , ' tcx > > {
42
44
/// Stores the `Machine` instance.
43
45
pub machine : M ,
@@ -95,7 +97,7 @@ pub struct Frame<'mir, 'tcx: 'mir> {
95
97
/// The locals are stored as `Option<Value>`s.
96
98
/// `None` represents a local that is currently dead, while a live local
97
99
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
98
- pub locals : IndexVec < mir:: Local , LocalValue > ,
100
+ pub locals : IndexVec < mir:: Local , LocalValue < AllocId > > ,
99
101
100
102
////////////////////////////////////////////////////////////////////////////////
101
103
// Current position within the function
@@ -108,51 +110,25 @@ pub struct Frame<'mir, 'tcx: 'mir> {
108
110
pub stmt : usize ,
109
111
}
110
112
111
- impl < ' mir , ' tcx : ' mir > Eq for Frame < ' mir , ' tcx > { }
112
-
113
- impl < ' mir , ' tcx : ' mir > PartialEq for Frame < ' mir , ' tcx > {
114
- fn eq ( & self , other : & Self ) -> bool {
115
- let Frame {
116
- mir : _,
117
- instance,
118
- span : _,
119
- return_to_block,
120
- return_place,
121
- locals,
122
- block,
123
- stmt,
124
- } = self ;
125
-
126
- // Some of these are constant during evaluation, but are included
127
- // anyways for correctness.
128
- * instance == other. instance
129
- && * return_to_block == other. return_to_block
130
- && * return_place == other. return_place
131
- && * locals == other. locals
132
- && * block == other. block
133
- && * stmt == other. stmt
134
- }
135
- }
113
+ impl < ' a , ' mir , ' tcx : ' mir > HashStable < StableHashingContext < ' a > > for Frame < ' mir , ' tcx > {
114
+ fn hash_stable < W : StableHasherResult > (
115
+ & self ,
116
+ hcx : & mut StableHashingContext < ' a > ,
117
+ hasher : & mut StableHasher < W > ) {
136
118
137
- impl < ' mir , ' tcx : ' mir > Hash for Frame < ' mir , ' tcx > {
138
- fn hash < H : Hasher > ( & self , state : & mut H ) {
139
119
let Frame {
140
- mir : _ ,
120
+ mir,
141
121
instance,
142
- span : _ ,
122
+ span,
143
123
return_to_block,
144
124
return_place,
145
125
locals,
146
126
block,
147
127
stmt,
148
128
} = self ;
149
129
150
- instance. hash ( state) ;
151
- return_to_block. hash ( state) ;
152
- return_place. hash ( state) ;
153
- locals. hash ( state) ;
154
- block. hash ( state) ;
155
- stmt. hash ( state) ;
130
+ ( mir, instance, span, return_to_block) . hash_stable ( hcx, hasher) ;
131
+ ( return_place, locals, block, stmt) . hash_stable ( hcx, hasher) ;
156
132
}
157
133
}
158
134
@@ -168,15 +144,27 @@ pub enum StackPopCleanup {
168
144
None { cleanup : bool } ,
169
145
}
170
146
147
+ impl < ' a > HashStable < StableHashingContext < ' a > > for StackPopCleanup {
148
+ fn hash_stable < W : StableHasherResult > (
149
+ & self ,
150
+ hcx : & mut StableHashingContext < ' a > ,
151
+ hasher : & mut StableHasher < W > ) {
152
+ match self {
153
+ StackPopCleanup :: Goto ( ref block) => block. hash_stable ( hcx, hasher) ,
154
+ StackPopCleanup :: None { cleanup } => cleanup. hash_stable ( hcx, hasher) ,
155
+ }
156
+ }
157
+ }
158
+
171
159
// State of a local variable
172
160
#[ derive( Copy , Clone , PartialEq , Eq , Hash ) ]
173
- pub enum LocalValue {
161
+ pub enum LocalValue < Id = AllocId > {
174
162
Dead ,
175
163
// Mostly for convenience, we re-use the `Operand` type here.
176
164
// This is an optimization over just always having a pointer here;
177
165
// we can thus avoid doing an allocation when the local just stores
178
166
// immediate values *and* never has its address taken.
179
- Live ( Operand ) ,
167
+ Live ( Operand < Id > ) ,
180
168
}
181
169
182
170
impl < ' tcx > LocalValue {
@@ -195,72 +183,10 @@ impl<'tcx> LocalValue {
195
183
}
196
184
}
197
185
198
- /// The virtual machine state during const-evaluation at a given point in time.
199
- type EvalSnapshot < ' a , ' mir , ' tcx , M >
200
- = ( M , Vec < Frame < ' mir , ' tcx > > , Memory < ' a , ' mir , ' tcx , M > ) ;
201
-
202
- pub ( super ) struct InfiniteLoopDetector < ' a , ' mir , ' tcx : ' a + ' mir , M : Machine < ' mir , ' tcx > > {
203
- /// The set of all `EvalSnapshot` *hashes* observed by this detector.
204
- ///
205
- /// When a collision occurs in this table, we store the full snapshot in
206
- /// `snapshots`.
207
- hashes : FxHashSet < u64 > ,
208
-
209
- /// The set of all `EvalSnapshot`s observed by this detector.
210
- ///
211
- /// An `EvalSnapshot` will only be fully cloned once it has caused a
212
- /// collision in `hashes`. As a result, the detector must observe at least
213
- /// *two* full cycles of an infinite loop before it triggers.
214
- snapshots : FxHashSet < EvalSnapshot < ' a , ' mir , ' tcx , M > > ,
215
- }
216
-
217
- impl < ' a , ' mir , ' tcx , M > Default for InfiniteLoopDetector < ' a , ' mir , ' tcx , M >
218
- where M : Machine < ' mir , ' tcx > ,
219
- ' tcx : ' a + ' mir ,
220
- {
221
- fn default ( ) -> Self {
222
- InfiniteLoopDetector {
223
- hashes : FxHashSet :: default ( ) ,
224
- snapshots : FxHashSet :: default ( ) ,
225
- }
226
- }
227
- }
228
-
229
- impl < ' a , ' mir , ' tcx , M > InfiniteLoopDetector < ' a , ' mir , ' tcx , M >
230
- where M : Machine < ' mir , ' tcx > ,
231
- ' tcx : ' a + ' mir ,
232
- {
233
- /// Returns `true` if the loop detector has not yet observed a snapshot.
234
- pub fn is_empty ( & self ) -> bool {
235
- self . hashes . is_empty ( )
236
- }
237
-
238
- pub fn observe_and_analyze (
239
- & mut self ,
240
- machine : & M ,
241
- stack : & Vec < Frame < ' mir , ' tcx > > ,
242
- memory : & Memory < ' a , ' mir , ' tcx , M > ,
243
- ) -> EvalResult < ' tcx , ( ) > {
244
- let snapshot = ( machine, stack, memory) ;
245
-
246
- let mut fx = FxHasher :: default ( ) ;
247
- snapshot. hash ( & mut fx) ;
248
- let hash = fx. finish ( ) ;
249
-
250
- if self . hashes . insert ( hash) {
251
- // No collision
252
- return Ok ( ( ) )
253
- }
254
-
255
- if self . snapshots . insert ( ( machine. clone ( ) , stack. clone ( ) , memory. clone ( ) ) ) {
256
- // Spurious collision or first cycle
257
- return Ok ( ( ) )
258
- }
259
-
260
- // Second cycle
261
- Err ( EvalErrorKind :: InfiniteLoop . into ( ) )
262
- }
263
- }
186
+ impl_stable_hash_for ! ( enum self :: LocalValue {
187
+ Dead ,
188
+ Live ( x) ,
189
+ } ) ;
264
190
265
191
impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > HasDataLayout for & ' a EvalContext < ' a , ' mir , ' tcx , M > {
266
192
#[ inline]
0 commit comments