@@ -43,85 +43,72 @@ pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
4343pub const COMMON_VTABLE_ENTRIES_SIZE : usize = 1 ;
4444pub const COMMON_VTABLE_ENTRIES_ALIGN : usize = 2 ;
4545
46- impl < ' tcx > TyCtxt < ' tcx > {
47- /// Retrieves an allocation that represents the contents of a vtable.
48- /// There's a cache within `TyCtxt` so it will be deduplicated.
49- pub fn vtable_allocation (
50- self ,
51- ty : Ty < ' tcx > ,
52- poly_trait_ref : Option < ty:: PolyExistentialTraitRef < ' tcx > > ,
53- ) -> AllocId {
54- let tcx = self ;
55- let vtables_cache = tcx. vtables_cache . lock ( ) ;
56- if let Some ( alloc_id) = vtables_cache. get ( & ( ty, poly_trait_ref) ) . cloned ( ) {
57- return alloc_id;
58- }
59- drop ( vtables_cache) ;
60-
61- let vtable_entries = if let Some ( poly_trait_ref) = poly_trait_ref {
62- let trait_ref = poly_trait_ref. with_self_ty ( tcx, ty) ;
63- let trait_ref = tcx. erase_regions ( trait_ref) ;
46+ /// Retrieves an allocation that represents the contents of a vtable.
47+ /// Since this is a query, allocations are cached and not duplicated.
48+ pub ( super ) fn vtable_allocation_provider < ' tcx > (
49+ tcx : TyCtxt < ' tcx > ,
50+ key : ( Ty < ' tcx > , Option < ty:: PolyExistentialTraitRef < ' tcx > > ) ,
51+ ) -> AllocId {
52+ let ( ty, poly_trait_ref) = key;
6453
65- tcx. vtable_entries ( trait_ref)
66- } else {
67- COMMON_VTABLE_ENTRIES
68- } ;
54+ let vtable_entries = if let Some ( poly_trait_ref) = poly_trait_ref {
55+ let trait_ref = poly_trait_ref. with_self_ty ( tcx, ty) ;
56+ let trait_ref = tcx. erase_regions ( trait_ref) ;
6957
70- let layout = tcx
71- . layout_of ( ty:: ParamEnv :: reveal_all ( ) . and ( ty) )
72- . expect ( "failed to build vtable representation" ) ;
73- assert ! ( !layout. is_unsized( ) , "can't create a vtable for an unsized type" ) ;
74- let size = layout. size . bytes ( ) ;
75- let align = layout. align . abi . bytes ( ) ;
58+ tcx. vtable_entries ( trait_ref)
59+ } else {
60+ COMMON_VTABLE_ENTRIES
61+ } ;
7662
77- let ptr_size = tcx. data_layout . pointer_size ;
78- let ptr_align = tcx. data_layout . pointer_align . abi ;
63+ let layout = tcx
64+ . layout_of ( ty:: ParamEnv :: reveal_all ( ) . and ( ty) )
65+ . expect ( "failed to build vtable representation" ) ;
66+ assert ! ( !layout. is_unsized( ) , "can't create a vtable for an unsized type" ) ;
67+ let size = layout. size . bytes ( ) ;
68+ let align = layout. align . abi . bytes ( ) ;
7969
80- let vtable_size = ptr_size * u64:: try_from ( vtable_entries. len ( ) ) . unwrap ( ) ;
81- let mut vtable =
82- Allocation :: uninit ( vtable_size, ptr_align, /* panic_on_fail */ true ) . unwrap ( ) ;
70+ let ptr_size = tcx. data_layout . pointer_size ;
71+ let ptr_align = tcx. data_layout . pointer_align . abi ;
8372
84- // No need to do any alignment checks on the memory accesses below, because we know the
85- // allocation is correctly aligned as we created it above. Also we're only offsetting by
86- // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
73+ let vtable_size = ptr_size * u64:: try_from ( vtable_entries. len ( ) ) . unwrap ( ) ;
74+ let mut vtable = Allocation :: uninit ( vtable_size, ptr_align, /* panic_on_fail */ true ) . unwrap ( ) ;
8775
88- for ( idx, entry) in vtable_entries. iter ( ) . enumerate ( ) {
89- let idx: u64 = u64:: try_from ( idx) . unwrap ( ) ;
90- let scalar = match entry {
91- VtblEntry :: MetadataDropInPlace => {
92- let instance = ty:: Instance :: resolve_drop_in_place ( tcx, ty) ;
93- let fn_alloc_id = tcx. create_fn_alloc ( instance) ;
94- let fn_ptr = Pointer :: from ( fn_alloc_id) ;
95- ScalarMaybeUninit :: from_pointer ( fn_ptr, & tcx)
96- }
97- VtblEntry :: MetadataSize => Scalar :: from_uint ( size, ptr_size) . into ( ) ,
98- VtblEntry :: MetadataAlign => Scalar :: from_uint ( align, ptr_size) . into ( ) ,
99- VtblEntry :: Vacant => continue ,
100- VtblEntry :: Method ( instance) => {
101- // Prepare the fn ptr we write into the vtable.
102- let instance = instance. polymorphize ( tcx) ;
103- let fn_alloc_id = tcx. create_fn_alloc ( instance) ;
104- let fn_ptr = Pointer :: from ( fn_alloc_id) ;
105- ScalarMaybeUninit :: from_pointer ( fn_ptr, & tcx)
106- }
107- VtblEntry :: TraitVPtr ( trait_ref) => {
108- let super_trait_ref = trait_ref. map_bound ( |trait_ref| {
109- ty:: ExistentialTraitRef :: erase_self_ty ( tcx, trait_ref)
110- } ) ;
111- let supertrait_alloc_id = self . vtable_allocation ( ty, Some ( super_trait_ref) ) ;
112- let vptr = Pointer :: from ( supertrait_alloc_id) ;
113- ScalarMaybeUninit :: from_pointer ( vptr, & tcx)
114- }
115- } ;
116- vtable
117- . write_scalar ( & tcx, alloc_range ( ptr_size * idx, ptr_size) , scalar)
118- . expect ( "failed to build vtable representation" ) ;
119- }
76+ // No need to do any alignment checks on the memory accesses below, because we know the
77+ // allocation is correctly aligned as we created it above. Also we're only offsetting by
78+ // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
12079
121- vtable. mutability = Mutability :: Not ;
122- let alloc_id = tcx. create_memory_alloc ( tcx. intern_const_alloc ( vtable) ) ;
123- let mut vtables_cache = self . vtables_cache . lock ( ) ;
124- vtables_cache. insert ( ( ty, poly_trait_ref) , alloc_id) ;
125- alloc_id
80+ for ( idx, entry) in vtable_entries. iter ( ) . enumerate ( ) {
81+ let idx: u64 = u64:: try_from ( idx) . unwrap ( ) ;
82+ let scalar = match entry {
83+ VtblEntry :: MetadataDropInPlace => {
84+ let instance = ty:: Instance :: resolve_drop_in_place ( tcx, ty) ;
85+ let fn_alloc_id = tcx. create_fn_alloc ( instance) ;
86+ let fn_ptr = Pointer :: from ( fn_alloc_id) ;
87+ ScalarMaybeUninit :: from_pointer ( fn_ptr, & tcx)
88+ }
89+ VtblEntry :: MetadataSize => Scalar :: from_uint ( size, ptr_size) . into ( ) ,
90+ VtblEntry :: MetadataAlign => Scalar :: from_uint ( align, ptr_size) . into ( ) ,
91+ VtblEntry :: Vacant => continue ,
92+ VtblEntry :: Method ( instance) => {
93+ // Prepare the fn ptr we write into the vtable.
94+ let instance = instance. polymorphize ( tcx) ;
95+ let fn_alloc_id = tcx. create_fn_alloc ( instance) ;
96+ let fn_ptr = Pointer :: from ( fn_alloc_id) ;
97+ ScalarMaybeUninit :: from_pointer ( fn_ptr, & tcx)
98+ }
99+ VtblEntry :: TraitVPtr ( trait_ref) => {
100+ let super_trait_ref = trait_ref
101+ . map_bound ( |trait_ref| ty:: ExistentialTraitRef :: erase_self_ty ( tcx, trait_ref) ) ;
102+ let supertrait_alloc_id = tcx. vtable_allocation ( ( ty, Some ( super_trait_ref) ) ) ;
103+ let vptr = Pointer :: from ( supertrait_alloc_id) ;
104+ ScalarMaybeUninit :: from_pointer ( vptr, & tcx)
105+ }
106+ } ;
107+ vtable
108+ . write_scalar ( & tcx, alloc_range ( ptr_size * idx, ptr_size) , scalar)
109+ . expect ( "failed to build vtable representation" ) ;
126110 }
111+
112+ vtable. mutability = Mutability :: Not ;
113+ tcx. create_memory_alloc ( tcx. intern_const_alloc ( vtable) )
127114}
0 commit comments