@@ -12,15 +12,13 @@ use std::fmt;
12
12
use std:: io;
13
13
use std:: io:: { Read , Write } ;
14
14
use std:: num:: NonZero ;
15
- use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
16
15
17
- use smallvec:: { smallvec, SmallVec } ;
18
16
use tracing:: { debug, trace} ;
19
17
20
18
use rustc_ast:: LitKind ;
21
19
use rustc_attr:: InlineAttr ;
22
20
use rustc_data_structures:: fx:: FxHashMap ;
23
- use rustc_data_structures:: sync:: { HashMapExt , Lock } ;
21
+ use rustc_data_structures:: sync:: Lock ;
24
22
use rustc_errors:: ErrorGuaranteed ;
25
23
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
26
24
use rustc_macros:: { HashStable , TyDecodable , TyEncodable , TypeFoldable , TypeVisitable } ;
@@ -159,14 +157,9 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
159
157
}
160
158
}
161
159
162
- // Used to avoid infinite recursion when decoding cyclic allocations.
163
- type DecodingSessionId = NonZero < u32 > ;
164
-
165
160
#[ derive( Clone ) ]
166
161
enum State {
167
162
Empty ,
168
- InProgressNonAlloc ( SmallVec < [ DecodingSessionId ; 1 ] > ) ,
169
- InProgress ( SmallVec < [ DecodingSessionId ; 1 ] > , AllocId ) ,
170
163
Done ( AllocId ) ,
171
164
}
172
165
@@ -180,13 +173,7 @@ pub struct AllocDecodingState {
180
173
impl AllocDecodingState {
181
174
#[ inline]
182
175
pub fn new_decoding_session ( & self ) -> AllocDecodingSession < ' _ > {
183
- static DECODER_SESSION_ID : AtomicU32 = AtomicU32 :: new ( 0 ) ;
184
- let counter = DECODER_SESSION_ID . fetch_add ( 1 , Ordering :: SeqCst ) ;
185
-
186
- // Make sure this is never zero.
187
- let session_id = DecodingSessionId :: new ( ( counter & 0x7FFFFFFF ) + 1 ) . unwrap ( ) ;
188
-
189
- AllocDecodingSession { state : self , session_id }
176
+ AllocDecodingSession { state : self }
190
177
}
191
178
192
179
pub fn new ( data_offsets : Vec < u64 > ) -> Self {
@@ -200,7 +187,6 @@ impl AllocDecodingState {
200
187
#[ derive( Copy , Clone ) ]
201
188
pub struct AllocDecodingSession < ' s > {
202
189
state : & ' s AllocDecodingState ,
203
- session_id : DecodingSessionId ,
204
190
}
205
191
206
192
impl < ' s > AllocDecodingSession < ' s > {
@@ -220,106 +206,62 @@ impl<'s> AllocDecodingSession<'s> {
220
206
( alloc_kind, decoder. position ( ) )
221
207
} ) ;
222
208
209
+ // We are going to hold this lock during the entire decoding of this allocation, which may
210
+ // require that we decode other allocations. This cannot deadlock for two reasons:
211
+ //
212
+ // At the time of writing, it is only possible to create an allocation that contains a pointer
213
+ // to itself using the const_allocate intrinsic (which is for testing only), and even attempting
214
+ // to evaluate such consts blows the stack. If we ever grow a mechanism for producing
215
+ // cyclic allocations, we will need a new strategy for decoding that doesn't bring back
216
+ // https://github.com/rust-lang/rust/issues/126741.
217
+ //
218
+ // It is also impossible to create two allocations (call them A and B) where A is a pointer to B, and B
219
+ // is a pointer to A, because attempting to evaluate either of those consts will produce a
220
+ // query cycle, failing compilation.
221
+ let mut entry = self . state . decoding_state [ idx] . lock ( ) ;
223
222
// Check the decoding state to see if it's already decoded or if we should
224
223
// decode it here.
225
- let alloc_id = {
226
- let mut entry = self . state . decoding_state [ idx] . lock ( ) ;
227
-
228
- match * entry {
229
- State :: Done ( alloc_id) => {
230
- return alloc_id;
231
- }
232
- ref mut entry @ State :: Empty => {
233
- // We are allowed to decode.
234
- match alloc_kind {
235
- AllocDiscriminant :: Alloc => {
236
- // If this is an allocation, we need to reserve an
237
- // `AllocId` so we can decode cyclic graphs.
238
- let alloc_id = decoder. interner ( ) . reserve_alloc_id ( ) ;
239
- * entry = State :: InProgress ( smallvec ! [ self . session_id] , alloc_id) ;
240
- Some ( alloc_id)
241
- }
242
- AllocDiscriminant :: Fn
243
- | AllocDiscriminant :: Static
244
- | AllocDiscriminant :: VTable => {
245
- // Fns and statics cannot be cyclic, and their `AllocId`
246
- // is determined later by interning.
247
- * entry = State :: InProgressNonAlloc ( smallvec ! [ self . session_id] ) ;
248
- None
249
- }
250
- }
251
- }
252
- State :: InProgressNonAlloc ( ref mut sessions) => {
253
- if sessions. contains ( & self . session_id ) {
254
- bug ! ( "this should be unreachable" ) ;
255
- } else {
256
- // Start decoding concurrently.
257
- sessions. push ( self . session_id ) ;
258
- None
259
- }
260
- }
261
- State :: InProgress ( ref mut sessions, alloc_id) => {
262
- if sessions. contains ( & self . session_id ) {
263
- // Don't recurse.
264
- return alloc_id;
265
- } else {
266
- // Start decoding concurrently.
267
- sessions. push ( self . session_id ) ;
268
- Some ( alloc_id)
269
- }
270
- }
271
- }
272
- } ;
224
+ if let State :: Done ( alloc_id) = * entry {
225
+ return alloc_id;
226
+ }
273
227
274
228
// Now decode the actual data.
275
229
let alloc_id = decoder. with_position ( pos, |decoder| {
276
230
match alloc_kind {
277
231
AllocDiscriminant :: Alloc => {
232
+ trace ! ( "creating memory alloc ID" ) ;
278
233
let alloc = <ConstAllocation < ' tcx > as Decodable < _ > >:: decode ( decoder) ;
279
- // We already have a reserved `AllocId`.
280
- let alloc_id = alloc_id. unwrap ( ) ;
281
- trace ! ( "decoded alloc {:?}: {:#?}" , alloc_id, alloc) ;
282
- decoder. interner ( ) . set_alloc_id_same_memory ( alloc_id, alloc) ;
283
- alloc_id
234
+ trace ! ( "decoded alloc {:?}" , alloc) ;
235
+ decoder. interner ( ) . reserve_and_set_memory_alloc ( alloc)
284
236
}
285
237
AllocDiscriminant :: Fn => {
286
- assert ! ( alloc_id. is_none( ) ) ;
287
238
trace ! ( "creating fn alloc ID" ) ;
288
239
let instance = ty:: Instance :: decode ( decoder) ;
289
240
trace ! ( "decoded fn alloc instance: {:?}" , instance) ;
290
241
let unique = bool:: decode ( decoder) ;
291
242
// Here we cannot call `reserve_and_set_fn_alloc` as that would use a query, which
292
243
// is not possible in this context. That's why the allocation stores
293
244
// whether it is unique or not.
294
- let alloc_id =
295
- decoder. interner ( ) . reserve_and_set_fn_alloc_internal ( instance, unique) ;
296
- alloc_id
245
+ decoder. interner ( ) . reserve_and_set_fn_alloc_internal ( instance, unique)
297
246
}
298
247
AllocDiscriminant :: VTable => {
299
- assert ! ( alloc_id. is_none( ) ) ;
300
248
trace ! ( "creating vtable alloc ID" ) ;
301
249
let ty = <Ty < ' _ > as Decodable < D > >:: decode ( decoder) ;
302
250
let poly_trait_ref =
303
251
<Option < ty:: PolyExistentialTraitRef < ' _ > > as Decodable < D > >:: decode ( decoder) ;
304
252
trace ! ( "decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}" ) ;
305
- let alloc_id =
306
- decoder. interner ( ) . reserve_and_set_vtable_alloc ( ty, poly_trait_ref) ;
307
- alloc_id
253
+ decoder. interner ( ) . reserve_and_set_vtable_alloc ( ty, poly_trait_ref)
308
254
}
309
255
AllocDiscriminant :: Static => {
310
- assert ! ( alloc_id. is_none( ) ) ;
311
256
trace ! ( "creating extern static alloc ID" ) ;
312
257
let did = <DefId as Decodable < D > >:: decode ( decoder) ;
313
258
trace ! ( "decoded static def-ID: {:?}" , did) ;
314
- let alloc_id = decoder. interner ( ) . reserve_and_set_static_alloc ( did) ;
315
- alloc_id
259
+ decoder. interner ( ) . reserve_and_set_static_alloc ( did)
316
260
}
317
261
}
318
262
} ) ;
319
263
320
- self . state . decoding_state [ idx] . with_lock ( |entry| {
321
- * entry = State :: Done ( alloc_id) ;
322
- } ) ;
264
+ * entry = State :: Done ( alloc_id) ;
323
265
324
266
alloc_id
325
267
}
@@ -563,12 +505,6 @@ impl<'tcx> TyCtxt<'tcx> {
563
505
bug ! ( "tried to set allocation ID {id:?}, but it was already existing as {old:#?}" ) ;
564
506
}
565
507
}
566
-
567
- /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
568
- /// twice for the same `(AllocId, Allocation)` pair.
569
- fn set_alloc_id_same_memory ( self , id : AllocId , mem : ConstAllocation < ' tcx > ) {
570
- self . alloc_map . lock ( ) . alloc_map . insert_same ( id, GlobalAlloc :: Memory ( mem) ) ;
571
- }
572
508
}
573
509
574
510
////////////////////////////////////////////////////////////////////////////////
0 commit comments