66//! The functionality in here is shared between persisting to crate metadata and
77//! persisting to incr. comp. caches.
88
9- use std:: marker:: PointeeSized ;
9+ use std:: hash:: Hash ;
10+ use std:: intrinsics;
11+ use std:: marker:: { DiscriminantKind , PointeeSized } ;
1012
1113use rustc_abi:: FieldIdx ;
14+ use rustc_data_structures:: fx:: FxHashMap ;
1215use rustc_hir:: def_id:: LocalDefId ;
1316use rustc_serialize:: { Decodable , Encodable } ;
14- use rustc_span:: Span ;
1517use rustc_span:: source_map:: Spanned ;
16- use rustc_type_ir :: codec as ir_codec ;
18+ use rustc_span :: { Span , SpanDecoder , SpanEncoder } ;
1719
1820use crate :: arena:: ArenaAllocatable ;
1921use crate :: infer:: canonical:: { CanonicalVarKind , CanonicalVarKinds } ;
@@ -22,13 +24,66 @@ use crate::mir::mono::MonoItem;
2224use crate :: ty:: { self , AdtDef , GenericArgsRef , Ty , TyCtxt } ;
2325use crate :: { mir, traits} ;
2426
25- pub trait TyEncoder < ' tcx > : ir_codec:: TyEncoder < ' tcx , Interner = TyCtxt < ' tcx > > { }
26- impl < ' tcx , T > TyEncoder < ' tcx > for T where T : ir_codec:: TyEncoder < ' tcx , Interner = TyCtxt < ' tcx > > { }
27+ /// The shorthand encoding uses an enum's variant index `usize`
28+ /// and is offset by this value so it never matches a real variant.
29+ /// This offset is also chosen so that the first byte is never < 0x80.
30+ pub const SHORTHAND_OFFSET : usize = 0x80 ;
2731
28- pub trait TyDecoder < ' tcx > : ir_codec :: TyDecoder < ' tcx , Interner = TyCtxt < ' tcx > > { }
29- impl < ' tcx , T > TyDecoder < ' tcx > for T where T : ir_codec :: TyDecoder < ' tcx , Interner = TyCtxt < ' tcx > > { }
32+ pub trait TyEncoder < ' tcx > : SpanEncoder {
33+ const CLEAR_CROSS_CRATE : bool ;
3034
31- pub use ir_codec:: { EncodableWithShorthand , SHORTHAND_OFFSET , encode_with_shorthand} ;
35+ fn position ( & self ) -> usize ;
36+
37+ fn type_shorthands ( & mut self ) -> & mut FxHashMap < Ty < ' tcx > , usize > ;
38+
39+ fn predicate_shorthands ( & mut self ) -> & mut FxHashMap < ty:: PredicateKind < ' tcx > , usize > ;
40+
41+ fn encode_alloc_id ( & mut self , alloc_id : & AllocId ) ;
42+ }
43+
44+ pub trait TyDecoder < ' tcx > : SpanDecoder {
45+ const CLEAR_CROSS_CRATE : bool ;
46+
47+ fn interner ( & self ) -> TyCtxt < ' tcx > ;
48+
49+ fn cached_ty_for_shorthand < F > ( & mut self , shorthand : usize , or_insert_with : F ) -> Ty < ' tcx >
50+ where
51+ F : FnOnce ( & mut Self ) -> Ty < ' tcx > ;
52+
53+ fn with_position < F , R > ( & mut self , pos : usize , f : F ) -> R
54+ where
55+ F : FnOnce ( & mut Self ) -> R ;
56+
57+ fn positioned_at_shorthand ( & self ) -> bool {
58+ ( self . peek_byte ( ) & ( SHORTHAND_OFFSET as u8 ) ) != 0
59+ }
60+
61+ fn decode_alloc_id ( & mut self ) -> AllocId ;
62+ }
63+
64+ pub trait EncodableWithShorthand < ' tcx , E : TyEncoder < ' tcx > > : Copy + Eq + Hash {
65+ type Variant : Encodable < E > ;
66+ fn variant ( & self ) -> & Self :: Variant ;
67+ }
68+
69+ #[ allow( rustc:: usage_of_ty_tykind) ]
70+ impl < ' tcx , E : TyEncoder < ' tcx > > EncodableWithShorthand < ' tcx , E > for Ty < ' tcx > {
71+ type Variant = ty:: TyKind < ' tcx > ;
72+
73+ #[ inline]
74+ fn variant ( & self ) -> & Self :: Variant {
75+ self . kind ( )
76+ }
77+ }
78+
79+ impl < ' tcx , E : TyEncoder < ' tcx > > EncodableWithShorthand < ' tcx , E > for ty:: PredicateKind < ' tcx > {
80+ type Variant = ty:: PredicateKind < ' tcx > ;
81+
82+ #[ inline]
83+ fn variant ( & self ) -> & Self :: Variant {
84+ self
85+ }
86+ }
3287
3388/// Trait for decoding to a reference.
3489///
@@ -44,6 +99,51 @@ pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>>: PointeeSized {
4499 fn decode ( d : & mut D ) -> & ' tcx Self ;
45100}
46101
102+ /// Encode the given value or a previously cached shorthand.
103+ pub fn encode_with_shorthand < ' tcx , E , T , M > ( encoder : & mut E , value : & T , cache : M )
104+ where
105+ E : TyEncoder < ' tcx > ,
106+ M : for < ' b > Fn ( & ' b mut E ) -> & ' b mut FxHashMap < T , usize > ,
107+ T : EncodableWithShorthand < ' tcx , E > ,
108+ // The discriminant and shorthand must have the same size.
109+ T :: Variant : DiscriminantKind < Discriminant = isize > ,
110+ {
111+ let existing_shorthand = cache ( encoder) . get ( value) . copied ( ) ;
112+ if let Some ( shorthand) = existing_shorthand {
113+ encoder. emit_usize ( shorthand) ;
114+ return ;
115+ }
116+
117+ let variant = value. variant ( ) ;
118+
119+ let start = encoder. position ( ) ;
120+ variant. encode ( encoder) ;
121+ let len = encoder. position ( ) - start;
122+
123+ // The shorthand encoding uses the same usize as the
124+ // discriminant, with an offset so they can't conflict.
125+ let discriminant = intrinsics:: discriminant_value ( variant) ;
126+ assert ! ( SHORTHAND_OFFSET > discriminant as usize ) ;
127+
128+ let shorthand = start + SHORTHAND_OFFSET ;
129+
130+ // Get the number of bits that leb128 could fit
131+ // in the same space as the fully encoded type.
132+ let leb128_bits = len * 7 ;
133+
134+ // Check that the shorthand is a not longer than the
135+ // full encoding itself, i.e., it's an obvious win.
136+ if leb128_bits >= 64 || ( shorthand as u64 ) < ( 1 << leb128_bits) {
137+ cache ( encoder) . insert ( * value, shorthand) ;
138+ }
139+ }
140+
141+ impl < ' tcx , E : TyEncoder < ' tcx > > Encodable < E > for Ty < ' tcx > {
142+ fn encode ( & self , e : & mut E ) {
143+ encode_with_shorthand ( e, self , TyEncoder :: type_shorthands) ;
144+ }
145+ }
146+
47147impl < ' tcx , E : TyEncoder < ' tcx > > Encodable < E > for ty:: Predicate < ' tcx > {
48148 fn encode ( & self , e : & mut E ) {
49149 let kind = self . kind ( ) ;
@@ -130,6 +230,25 @@ fn decode_arena_allocable_slice<
130230 decoder. interner ( ) . arena . alloc_from_iter ( <Vec < T > as Decodable < D > >:: decode ( decoder) )
131231}
132232
233+ impl < ' tcx , D : TyDecoder < ' tcx > > Decodable < D > for Ty < ' tcx > {
234+ #[ allow( rustc:: usage_of_ty_tykind) ]
235+ fn decode ( decoder : & mut D ) -> Ty < ' tcx > {
236+ // Handle shorthands first, if we have a usize > 0x80.
237+ if decoder. positioned_at_shorthand ( ) {
238+ let pos = decoder. read_usize ( ) ;
239+ assert ! ( pos >= SHORTHAND_OFFSET ) ;
240+ let shorthand = pos - SHORTHAND_OFFSET ;
241+
242+ decoder. cached_ty_for_shorthand ( shorthand, |decoder| {
243+ decoder. with_position ( shorthand, Ty :: decode)
244+ } )
245+ } else {
246+ let tcx = decoder. interner ( ) ;
247+ tcx. mk_ty_from_kind ( ty:: TyKind :: decode ( decoder) )
248+ }
249+ }
250+ }
251+
133252impl < ' tcx , D : TyDecoder < ' tcx > > Decodable < D > for ty:: Predicate < ' tcx > {
134253 fn decode ( decoder : & mut D ) -> ty:: Predicate < ' tcx > {
135254 let bound_vars = Decodable :: decode ( decoder) ;
0 commit comments