99// except according to those terms.
1010
1111use std:: fmt:: Write ;
12- use std:: hash:: { Hash , Hasher } ;
1312use std:: mem;
1413
1514use rustc:: hir:: def_id:: DefId ;
1615use rustc:: hir:: def:: Def ;
1716use rustc:: hir:: map:: definitions:: DefPathData ;
17+ use rustc:: ich:: StableHashingContext ;
1818use rustc:: mir;
1919use rustc:: ty:: layout:: {
2020 self , Size , Align , HasDataLayout , LayoutOf , TyLayout
2121} ;
2222use rustc:: ty:: subst:: { Subst , Substs } ;
2323use rustc:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
2424use rustc:: ty:: query:: TyCtxtAt ;
25- use rustc_data_structures:: fx:: { FxHashSet , FxHasher } ;
2625use rustc_data_structures:: indexed_vec:: IndexVec ;
26+ use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher , StableHasherResult } ;
2727use rustc:: mir:: interpret:: {
28- GlobalId , Scalar , FrameInfo ,
28+ GlobalId , Scalar , FrameInfo , AllocId ,
2929 EvalResult , EvalErrorKind ,
3030 ScalarMaybeUndef ,
3131 truncate, sign_extend,
@@ -38,6 +38,8 @@ use super::{
3838 Memory , Machine
3939} ;
4040
41+ use super :: snapshot:: InfiniteLoopDetector ;
42+
4143pub struct EvalContext < ' a , ' mir , ' tcx : ' a + ' mir , M : Machine < ' mir , ' tcx > > {
4244 /// Stores the `Machine` instance.
4345 pub machine : M ,
@@ -95,7 +97,7 @@ pub struct Frame<'mir, 'tcx: 'mir> {
9597 /// The locals are stored as `Option<Value>`s.
9698 /// `None` represents a local that is currently dead, while a live local
9799 /// 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 > > ,
99101
100102 ////////////////////////////////////////////////////////////////////////////////
101103 // Current position within the function
@@ -108,51 +110,25 @@ pub struct Frame<'mir, 'tcx: 'mir> {
108110 pub stmt : usize ,
109111}
110112
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 > ) {
136118
137- impl < ' mir , ' tcx : ' mir > Hash for Frame < ' mir , ' tcx > {
138- fn hash < H : Hasher > ( & self , state : & mut H ) {
139119 let Frame {
140- mir : _ ,
120+ mir,
141121 instance,
142- span : _ ,
122+ span,
143123 return_to_block,
144124 return_place,
145125 locals,
146126 block,
147127 stmt,
148128 } = self ;
149129
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) ;
156132 }
157133}
158134
@@ -168,15 +144,27 @@ pub enum StackPopCleanup {
168144 None { cleanup : bool } ,
169145}
170146
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+
171159// State of a local variable
172160#[ derive( Copy , Clone , PartialEq , Eq , Hash ) ]
173- pub enum LocalValue {
161+ pub enum LocalValue < Id = AllocId > {
174162 Dead ,
175163 // Mostly for convenience, we re-use the `Operand` type here.
176164 // This is an optimization over just always having a pointer here;
177165 // we can thus avoid doing an allocation when the local just stores
178166 // immediate values *and* never has its address taken.
179- Live ( Operand ) ,
167+ Live ( Operand < Id > ) ,
180168}
181169
182170impl < ' tcx > LocalValue {
@@ -195,72 +183,10 @@ impl<'tcx> LocalValue {
195183 }
196184}
197185
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+ } ) ;
264190
265191impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > HasDataLayout for & ' a EvalContext < ' a , ' mir , ' tcx , M > {
266192 #[ inline]
0 commit comments