1
1
use std:: convert:: TryFrom ;
2
2
3
3
use rustc_middle:: mir:: interpret:: { InterpResult , Pointer , PointerArithmetic , Scalar } ;
4
- use rustc_middle:: ty:: { self , Instance , Ty } ;
4
+ use rustc_middle:: ty:: {
5
+ self , Instance , Ty , VtblEntry , COMMON_VTABLE_ENTRIES , COMMON_VTABLE_ENTRIES_ALIGN ,
6
+ COMMON_VTABLE_ENTRIES_DROPINPLACE , COMMON_VTABLE_ENTRIES_SIZE ,
7
+ } ;
5
8
use rustc_target:: abi:: { Align , LayoutOf , Size } ;
6
9
7
10
use super :: util:: ensure_monomorphic_enough;
@@ -35,13 +38,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
35
38
return Ok ( vtable) ;
36
39
}
37
40
38
- let methods = if let Some ( poly_trait_ref) = poly_trait_ref {
41
+ let vtable_entries = if let Some ( poly_trait_ref) = poly_trait_ref {
39
42
let trait_ref = poly_trait_ref. with_self_ty ( * self . tcx , ty) ;
40
43
let trait_ref = self . tcx . erase_regions ( trait_ref) ;
41
44
42
- self . tcx . vtable_methods ( trait_ref)
45
+ self . tcx . vtable_entries ( trait_ref)
43
46
} else {
44
- & [ ]
47
+ COMMON_VTABLE_ENTRIES
45
48
} ;
46
49
47
50
let layout = self . layout_of ( ty) ?;
@@ -56,38 +59,41 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
56
59
// If you touch this code, be sure to also make the corresponding changes to
57
60
// `get_vtable` in `rust_codegen_llvm/meth.rs`.
58
61
// /////////////////////////////////////////////////////////////////////////////////////////
59
- let vtable_size = ptr_size * u64:: try_from ( methods . len ( ) ) . unwrap ( ) . checked_add ( 3 ) . unwrap ( ) ;
62
+ let vtable_size = ptr_size * u64:: try_from ( vtable_entries . len ( ) ) . unwrap ( ) ;
60
63
let vtable = self . memory . allocate ( vtable_size, ptr_align, MemoryKind :: Vtable ) ;
61
64
62
65
let drop = Instance :: resolve_drop_in_place ( tcx, ty) ;
63
66
let drop = self . memory . create_fn_alloc ( FnVal :: Instance ( drop) ) ;
64
67
65
- // Prepare the fn ptrs we will write into the vtable later.
66
- let fn_ptrs = methods
67
- . iter ( )
68
- . enumerate ( ) // remember the original position
69
- . filter_map ( |( i, method) | {
70
- if let Some ( ( def_id, substs) ) = method { Some ( ( i, def_id, substs) ) } else { None }
71
- } )
72
- . map ( |( i, def_id, substs) | {
73
- let instance =
74
- ty:: Instance :: resolve_for_vtable ( tcx, self . param_env , * def_id, substs)
75
- . ok_or_else ( || err_inval ! ( TooGeneric ) ) ?;
76
- Ok ( ( i, self . memory . create_fn_alloc ( FnVal :: Instance ( instance) ) ) )
77
- } )
78
- . collect :: < InterpResult < ' tcx , Vec < ( usize , Pointer < M :: PointerTag > ) > > > ( ) ?;
79
-
80
68
// No need to do any alignment checks on the memory accesses below, because we know the
81
69
// allocation is correctly aligned as we created it above. Also we're only offsetting by
82
70
// multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
71
+ let scalars = vtable_entries
72
+ . iter ( )
73
+ . map ( |entry| -> InterpResult < ' tcx , _ > {
74
+ match entry {
75
+ VtblEntry :: MetadataDropInPlace => Ok ( Some ( drop. into ( ) ) ) ,
76
+ VtblEntry :: MetadataSize => Ok ( Some ( Scalar :: from_uint ( size, ptr_size) . into ( ) ) ) ,
77
+ VtblEntry :: MetadataAlign => Ok ( Some ( Scalar :: from_uint ( align, ptr_size) . into ( ) ) ) ,
78
+ VtblEntry :: Vacant => Ok ( None ) ,
79
+ VtblEntry :: Method ( def_id, substs) => {
80
+ // Prepare the fn ptr we write into the vtable.
81
+ let instance =
82
+ ty:: Instance :: resolve_for_vtable ( tcx, self . param_env , * def_id, substs)
83
+ . ok_or_else ( || err_inval ! ( TooGeneric ) ) ?;
84
+ let fn_ptr = self . memory . create_fn_alloc ( FnVal :: Instance ( instance) ) ;
85
+ Ok ( Some ( fn_ptr. into ( ) ) )
86
+ }
87
+ }
88
+ } )
89
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
83
90
let mut vtable_alloc =
84
91
self . memory . get_mut ( vtable. into ( ) , vtable_size, ptr_align) ?. expect ( "not a ZST" ) ;
85
- vtable_alloc. write_ptr_sized ( ptr_size * 0 , drop. into ( ) ) ?;
86
- vtable_alloc. write_ptr_sized ( ptr_size * 1 , Scalar :: from_uint ( size, ptr_size) . into ( ) ) ?;
87
- vtable_alloc. write_ptr_sized ( ptr_size * 2 , Scalar :: from_uint ( align, ptr_size) . into ( ) ) ?;
88
-
89
- for ( i, fn_ptr) in fn_ptrs. into_iter ( ) {
90
- vtable_alloc. write_ptr_sized ( ptr_size * ( 3 + i as u64 ) , fn_ptr. into ( ) ) ?;
92
+ for ( idx, scalar) in scalars. into_iter ( ) . enumerate ( ) {
93
+ if let Some ( scalar) = scalar {
94
+ let idx: u64 = u64:: try_from ( idx) . unwrap ( ) ;
95
+ vtable_alloc. write_ptr_sized ( ptr_size * idx, scalar) ?;
96
+ }
91
97
}
92
98
93
99
M :: after_static_mem_initialized ( self , vtable, vtable_size) ?;
@@ -99,16 +105,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
99
105
}
100
106
101
107
/// Resolves the function at the specified slot in the provided
102
- /// vtable. An index of '0' corresponds to the first method
103
- /// declared in the trait of the provided vtable.
108
+ /// vtable. Currently an index of '3' (`COMMON_VTABLE_ENTRIES.len()`)
109
+ /// corresponds to the first method declared in the trait of the provided vtable.
104
110
pub fn get_vtable_slot (
105
111
& self ,
106
112
vtable : Scalar < M :: PointerTag > ,
107
113
idx : u64 ,
108
114
) -> InterpResult < ' tcx , FnVal < ' tcx , M :: ExtraFnVal > > {
109
115
let ptr_size = self . pointer_size ( ) ;
110
- // Skip over the 'drop_ptr', 'size', and 'align' fields.
111
- let vtable_slot = vtable. ptr_offset ( ptr_size * idx. checked_add ( 3 ) . unwrap ( ) , self ) ?;
116
+ let vtable_slot = vtable. ptr_offset ( ptr_size * idx, self ) ?;
112
117
let vtable_slot = self
113
118
. memory
114
119
. get ( vtable_slot, ptr_size, self . tcx . data_layout . pointer_align . abi ) ?
@@ -122,12 +127,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
122
127
& self ,
123
128
vtable : Scalar < M :: PointerTag > ,
124
129
) -> InterpResult < ' tcx , ( ty:: Instance < ' tcx > , Ty < ' tcx > ) > {
130
+ let pointer_size = self . pointer_size ( ) ;
125
131
// We don't care about the pointee type; we just want a pointer.
126
132
let vtable = self
127
133
. memory
128
- . get ( vtable, self . tcx . data_layout . pointer_size , self . tcx . data_layout . pointer_align . abi ) ?
134
+ . get (
135
+ vtable,
136
+ pointer_size * u64:: try_from ( COMMON_VTABLE_ENTRIES . len ( ) ) . unwrap ( ) ,
137
+ self . tcx . data_layout . pointer_align . abi ,
138
+ ) ?
129
139
. expect ( "cannot be a ZST" ) ;
130
- let drop_fn = vtable. read_ptr_sized ( Size :: ZERO ) ?. check_init ( ) ?;
140
+ let drop_fn = vtable
141
+ . read_ptr_sized (
142
+ pointer_size * u64:: try_from ( COMMON_VTABLE_ENTRIES_DROPINPLACE ) . unwrap ( ) ,
143
+ ) ?
144
+ . check_init ( ) ?;
131
145
// We *need* an instance here, no other kind of function value, to be able
132
146
// to determine the type.
133
147
let drop_instance = self . memory . get_fn ( drop_fn) ?. as_instance ( ) ?;
@@ -153,11 +167,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
153
167
// the size, and the align (which we read below).
154
168
let vtable = self
155
169
. memory
156
- . get ( vtable, 3 * pointer_size, self . tcx . data_layout . pointer_align . abi ) ?
170
+ . get (
171
+ vtable,
172
+ pointer_size * u64:: try_from ( COMMON_VTABLE_ENTRIES . len ( ) ) . unwrap ( ) ,
173
+ self . tcx . data_layout . pointer_align . abi ,
174
+ ) ?
157
175
. expect ( "cannot be a ZST" ) ;
158
- let size = vtable. read_ptr_sized ( pointer_size) ?. check_init ( ) ?;
176
+ let size = vtable
177
+ . read_ptr_sized ( pointer_size * u64:: try_from ( COMMON_VTABLE_ENTRIES_SIZE ) . unwrap ( ) ) ?
178
+ . check_init ( ) ?;
159
179
let size = u64:: try_from ( self . force_bits ( size, pointer_size) ?) . unwrap ( ) ;
160
- let align = vtable. read_ptr_sized ( pointer_size * 2 ) ?. check_init ( ) ?;
180
+ let align = vtable
181
+ . read_ptr_sized ( pointer_size * u64:: try_from ( COMMON_VTABLE_ENTRIES_ALIGN ) . unwrap ( ) ) ?
182
+ . check_init ( ) ?;
161
183
let align = u64:: try_from ( self . force_bits ( align, pointer_size) ?) . unwrap ( ) ;
162
184
let align = Align :: from_bytes ( align) . map_err ( |e| err_ub ! ( InvalidVtableAlignment ( e) ) ) ?;
163
185
0 commit comments