@@ -16,13 +16,15 @@ use std::collections::BTreeMap;
16
16
use std:: fmt;
17
17
use mir;
18
18
use hir:: def_id:: DefId ;
19
- use ty:: { self , TyCtxt } ;
19
+ use ty:: { self , TyCtxt , Instance } ;
20
20
use ty:: layout:: { self , Align , HasDataLayout , Size } ;
21
21
use middle:: region;
22
22
use std:: iter;
23
23
use std:: io;
24
+ use std:: hash:: Hash ;
24
25
use syntax:: ast:: Mutability ;
25
26
use rustc_serialize:: { Encoder , Decoder , Decodable , Encodable } ;
27
+ use rustc_data_structures:: fx:: FxHashMap ;
26
28
use byteorder:: { WriteBytesExt , ReadBytesExt , LittleEndian , BigEndian } ;
27
29
28
30
#[ derive( Clone , Debug , PartialEq , RustcEncodable , RustcDecodable ) ]
@@ -150,7 +152,7 @@ impl<'tcx> MemoryPointer {
150
152
}
151
153
152
154
153
- #[ derive( Copy , Clone , Default , Eq , Hash , Ord , PartialEq , PartialOrd , Debug ) ]
155
+ #[ derive( Copy , Clone , Eq , Hash , Ord , PartialEq , PartialOrd , Debug ) ]
154
156
pub struct AllocId ( pub u64 ) ;
155
157
156
158
impl :: rustc_serialize:: UseSpecializedEncodable for AllocId { }
@@ -171,20 +173,25 @@ pub fn specialized_encode_alloc_id<
171
173
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
172
174
alloc_id : AllocId ,
173
175
) -> Result < ( ) , E :: Error > {
174
- if let Some ( alloc) = tcx. interpret_interner . get_alloc ( alloc_id) {
175
- trace ! ( "encoding {:?} with {:#?}" , alloc_id, alloc) ;
176
- AllocKind :: Alloc . encode ( encoder) ?;
177
- alloc. encode ( encoder) ?;
178
- } else if let Some ( fn_instance) = tcx. interpret_interner . get_fn ( alloc_id) {
179
- trace ! ( "encoding {:?} with {:#?}" , alloc_id, fn_instance) ;
180
- AllocKind :: Fn . encode ( encoder) ?;
181
- fn_instance. encode ( encoder) ?;
182
- } else if let Some ( did) = tcx. interpret_interner . get_static ( alloc_id) {
183
- // referring to statics doesn't need to know about their allocations, just about its DefId
184
- AllocKind :: Static . encode ( encoder) ?;
185
- did. encode ( encoder) ?;
186
- } else {
187
- bug ! ( "alloc id without corresponding allocation: {}" , alloc_id) ;
176
+ let alloc_type: AllocType < ' tcx , & ' tcx Allocation > =
177
+ tcx. alloc_map . lock ( ) . get ( alloc_id) . expect ( "no value for AllocId" ) ;
178
+ match alloc_type {
179
+ AllocType :: Memory ( alloc) => {
180
+ trace ! ( "encoding {:?} with {:#?}" , alloc_id, alloc) ;
181
+ AllocKind :: Alloc . encode ( encoder) ?;
182
+ alloc. encode ( encoder) ?;
183
+ }
184
+ AllocType :: Function ( fn_instance) => {
185
+ trace ! ( "encoding {:?} with {:#?}" , alloc_id, fn_instance) ;
186
+ AllocKind :: Fn . encode ( encoder) ?;
187
+ fn_instance. encode ( encoder) ?;
188
+ }
189
+ AllocType :: Static ( did) => {
190
+ // referring to statics doesn't need to know about their allocations,
191
+ // just about its DefId
192
+ AllocKind :: Static . encode ( encoder) ?;
193
+ did. encode ( encoder) ?;
194
+ }
188
195
}
189
196
Ok ( ( ) )
190
197
}
@@ -200,31 +207,30 @@ pub fn specialized_decode_alloc_id<
200
207
) -> Result < AllocId , D :: Error > {
201
208
match AllocKind :: decode ( decoder) ? {
202
209
AllocKind :: Alloc => {
203
- let alloc_id = tcx. interpret_interner . reserve ( ) ;
210
+ let alloc_id = tcx. alloc_map . lock ( ) . reserve ( ) ;
204
211
trace ! ( "creating alloc id {:?}" , alloc_id) ;
205
212
// insert early to allow recursive allocs
206
213
cache ( decoder, alloc_id) ;
207
214
208
- let allocation = Allocation :: decode ( decoder) ?;
215
+ let allocation = < & ' tcx Allocation as Decodable > :: decode ( decoder) ?;
209
216
trace ! ( "decoded alloc {:?} {:#?}" , alloc_id, allocation) ;
210
- let allocation = tcx. intern_const_alloc ( allocation) ;
211
- tcx. interpret_interner . intern_at_reserved ( alloc_id, allocation) ;
217
+ tcx. alloc_map . lock ( ) . set_id_memory ( alloc_id, allocation) ;
212
218
213
219
Ok ( alloc_id)
214
220
} ,
215
221
AllocKind :: Fn => {
216
222
trace ! ( "creating fn alloc id" ) ;
217
223
let instance = ty:: Instance :: decode ( decoder) ?;
218
224
trace ! ( "decoded fn alloc instance: {:?}" , instance) ;
219
- let id = tcx. interpret_interner . create_fn_alloc ( instance) ;
225
+ let id = tcx. alloc_map . lock ( ) . create_fn_alloc ( instance) ;
220
226
trace ! ( "created fn alloc id: {:?}" , id) ;
221
227
cache ( decoder, id) ;
222
228
Ok ( id)
223
229
} ,
224
230
AllocKind :: Static => {
225
231
trace ! ( "creating extern static alloc id at" ) ;
226
232
let did = DefId :: decode ( decoder) ?;
227
- let alloc_id = tcx. interpret_interner . cache_static ( did) ;
233
+ let alloc_id = tcx. alloc_map . lock ( ) . intern_static ( did) ;
228
234
cache ( decoder, alloc_id) ;
229
235
Ok ( alloc_id)
230
236
} ,
@@ -237,6 +243,97 @@ impl fmt::Display for AllocId {
237
243
}
238
244
}
239
245
246
+ #[ derive( Debug , Clone , Eq , PartialEq , Hash , RustcDecodable , RustcEncodable ) ]
247
+ pub enum AllocType < ' tcx , M > {
248
+ /// The alloc id is used as a function pointer
249
+ Function ( Instance < ' tcx > ) ,
250
+ /// The alloc id points to a static variable
251
+ Static ( DefId ) ,
252
+ /// The alloc id points to memory
253
+ Memory ( M )
254
+ }
255
+
256
+ pub struct AllocMap < ' tcx , M > {
257
+ /// Lets you know what an AllocId refers to
258
+ id_to_type : FxHashMap < AllocId , AllocType < ' tcx , M > > ,
259
+
260
+ /// Used to ensure that functions and statics only get one associated AllocId
261
+ type_interner : FxHashMap < AllocType < ' tcx , M > , AllocId > ,
262
+
263
+ /// The AllocId to assign to the next requested id.
264
+ /// Always incremented, never gets smaller.
265
+ next_id : AllocId ,
266
+ }
267
+
268
+ impl < ' tcx , M : fmt:: Debug + Eq + Hash + Clone > AllocMap < ' tcx , M > {
269
+ pub fn new ( ) -> Self {
270
+ AllocMap {
271
+ id_to_type : FxHashMap ( ) ,
272
+ type_interner : FxHashMap ( ) ,
273
+ next_id : AllocId ( 0 ) ,
274
+ }
275
+ }
276
+
277
+ /// obtains a new allocation ID that can be referenced but does not
278
+ /// yet have an allocation backing it.
279
+ pub fn reserve (
280
+ & mut self ,
281
+ ) -> AllocId {
282
+ let next = self . next_id ;
283
+ self . next_id . 0 = self . next_id . 0
284
+ . checked_add ( 1 )
285
+ . expect ( "You overflowed a u64 by incrementing by 1... \
286
+ You've just earned yourself a free drink if we ever meet. \
287
+ Seriously, how did you do that?!") ;
288
+ next
289
+ }
290
+
291
+ fn intern ( & mut self , alloc_type : AllocType < ' tcx , M > ) -> AllocId {
292
+ if let Some ( & alloc_id) = self . type_interner . get ( & alloc_type) {
293
+ return alloc_id;
294
+ }
295
+ let id = self . reserve ( ) ;
296
+ debug ! ( "creating alloc_type {:?} with id {}" , alloc_type, id) ;
297
+ self . id_to_type . insert ( id, alloc_type. clone ( ) ) ;
298
+ self . type_interner . insert ( alloc_type, id) ;
299
+ id
300
+ }
301
+
302
+ // FIXME: Check if functions have identity. If not, we should not intern these,
303
+ // but instead create a new id per use.
304
+ // Alternatively we could just make comparing function pointers an error.
305
+ pub fn create_fn_alloc ( & mut self , instance : Instance < ' tcx > ) -> AllocId {
306
+ self . intern ( AllocType :: Function ( instance) )
307
+ }
308
+
309
+ pub fn get ( & self , id : AllocId ) -> Option < AllocType < ' tcx , M > > {
310
+ self . id_to_type . get ( & id) . cloned ( )
311
+ }
312
+
313
+ pub fn unwrap_memory ( & self , id : AllocId ) -> M {
314
+ match self . get ( id) {
315
+ Some ( AllocType :: Memory ( mem) ) => mem,
316
+ _ => bug ! ( "expected allocation id {} to point to memory" , id) ,
317
+ }
318
+ }
319
+
320
+ pub fn intern_static ( & mut self , static_id : DefId ) -> AllocId {
321
+ self . intern ( AllocType :: Static ( static_id) )
322
+ }
323
+
324
+ pub fn allocate ( & mut self , mem : M ) -> AllocId {
325
+ let id = self . reserve ( ) ;
326
+ self . set_id_memory ( id, mem) ;
327
+ id
328
+ }
329
+
330
+ pub fn set_id_memory ( & mut self , id : AllocId , mem : M ) {
331
+ if let Some ( old) = self . id_to_type . insert ( id, AllocType :: Memory ( mem) ) {
332
+ bug ! ( "tried to set allocation id {}, but it was already existing as {:#?}" , id, old) ;
333
+ }
334
+ }
335
+ }
336
+
240
337
#[ derive( Clone , Debug , Eq , PartialEq , Hash , RustcEncodable , RustcDecodable ) ]
241
338
pub struct Allocation {
242
339
/// The actual bytes of the allocation.
0 commit comments