1
1
use crate :: traits:: * ;
2
2
3
- use rustc_middle:: ty:: { self , Ty } ;
3
+ use rustc_middle:: ty:: { self , subst:: GenericArgKind , ExistentialPredicate , Ty , TyCtxt } ;
4
+ use rustc_session:: config:: Lto ;
5
+ use rustc_symbol_mangling:: typeid_for_trait_ref;
4
6
use rustc_target:: abi:: call:: FnAbi ;
5
7
6
8
#[ derive( Copy , Clone , Debug ) ]
@@ -15,20 +17,32 @@ impl<'a, 'tcx> VirtualIndex {
15
17
self ,
16
18
bx : & mut Bx ,
17
19
llvtable : Bx :: Value ,
20
+ ty : Ty < ' tcx > ,
18
21
fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
19
22
) -> Bx :: Value {
20
23
// Load the data pointer from the object.
21
- debug ! ( "get_fn({:?}, {:?})" , llvtable, self ) ;
22
-
24
+ debug ! ( "get_fn({llvtable:?}, {ty:?}, {self:?})" ) ;
23
25
let llty = bx. fn_ptr_backend_type ( fn_abi) ;
24
26
let llvtable = bx. pointercast ( llvtable, bx. type_ptr_to ( llty) ) ;
25
- let ptr_align = bx. tcx ( ) . data_layout . pointer_align . abi ;
26
- let gep = bx. inbounds_gep ( llty, llvtable, & [ bx. const_usize ( self . 0 ) ] ) ;
27
- let ptr = bx. load ( llty, gep, ptr_align) ;
28
- bx. nonnull_metadata ( ptr) ;
29
- // Vtable loads are invariant.
30
- bx. set_invariant_load ( ptr) ;
31
- ptr
27
+
28
+ if bx. cx ( ) . sess ( ) . opts . debugging_opts . virtual_function_elimination
29
+ && bx. cx ( ) . sess ( ) . lto ( ) == Lto :: Fat
30
+ {
31
+ let typeid =
32
+ bx. typeid_metadata ( typeid_for_trait_ref ( bx. tcx ( ) , get_trait_ref ( bx. tcx ( ) , ty) ) ) ;
33
+ let vtable_byte_offset = self . 0 * bx. data_layout ( ) . pointer_size . bytes ( ) ;
34
+ let type_checked_load = bx. type_checked_load ( llvtable, vtable_byte_offset, typeid) ;
35
+ let func = bx. extract_value ( type_checked_load, 0 ) ;
36
+ bx. pointercast ( func, llty)
37
+ } else {
38
+ let ptr_align = bx. tcx ( ) . data_layout . pointer_align . abi ;
39
+ let gep = bx. inbounds_gep ( llty, llvtable, & [ bx. const_usize ( self . 0 ) ] ) ;
40
+ let ptr = bx. load ( llty, gep, ptr_align) ;
41
+ bx. nonnull_metadata ( ptr) ;
42
+ // Vtable loads are invariant.
43
+ bx. set_invariant_load ( ptr) ;
44
+ ptr
45
+ }
32
46
}
33
47
34
48
pub fn get_usize < Bx : BuilderMethods < ' a , ' tcx > > (
@@ -50,6 +64,24 @@ impl<'a, 'tcx> VirtualIndex {
50
64
}
51
65
}
52
66
67
+ fn get_trait_ref < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> ty:: PolyExistentialTraitRef < ' tcx > {
68
+ for arg in ty. peel_refs ( ) . walk ( ) {
69
+ if let GenericArgKind :: Type ( ty) = arg. unpack ( ) {
70
+ if let ty:: Dynamic ( trait_refs, _) = ty. kind ( ) {
71
+ return trait_refs[ 0 ] . map_bound ( |trait_ref| match trait_ref {
72
+ ExistentialPredicate :: Trait ( tr) => tr,
73
+ ExistentialPredicate :: Projection ( proj) => proj. trait_ref ( tcx) ,
74
+ ExistentialPredicate :: AutoTrait ( _) => {
75
+ bug ! ( "auto traits don't have functions" )
76
+ }
77
+ } ) ;
78
+ }
79
+ }
80
+ }
81
+
82
+ bug ! ( "expected a `dyn Trait` ty, found {ty:?}" )
83
+ }
84
+
53
85
/// Creates a dynamic vtable for the given type and vtable origin.
54
86
/// This is used only for objects.
55
87
///
0 commit comments