@@ -4,8 +4,66 @@ use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
4
4
use ir:: context:: { BindgenContext , ItemId } ;
5
5
use ir:: traversal:: EdgeKind ;
6
6
use ir:: ty:: TypeKind ;
7
+ use std:: cmp;
7
8
use std:: collections:: HashMap ;
8
- use std:: collections:: HashSet ;
9
+ use std:: collections:: hash_map:: Entry ;
10
+ use std:: ops;
11
+
12
+ /// The result of the `HasVtableAnalysis` for an individual item.
13
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , Ord ) ]
14
+ pub enum HasVtableResult {
15
+ /// The item has a vtable, but the actual vtable pointer is in a base
16
+ /// member.
17
+ BaseHasVtable ,
18
+
19
+ /// The item has a vtable and the actual vtable pointer is within this item.
20
+ SelfHasVtable ,
21
+
22
+ /// The item does not have a vtable pointer.
23
+ No
24
+ }
25
+
26
+ impl Default for HasVtableResult {
27
+ fn default ( ) -> Self {
28
+ HasVtableResult :: No
29
+ }
30
+ }
31
+
32
+ impl cmp:: PartialOrd for HasVtableResult {
33
+ fn partial_cmp ( & self , rhs : & Self ) -> Option < cmp:: Ordering > {
34
+ use self :: HasVtableResult :: * ;
35
+
36
+ match ( * self , * rhs) {
37
+ ( x, y) if x == y => Some ( cmp:: Ordering :: Equal ) ,
38
+ ( BaseHasVtable , _) => Some ( cmp:: Ordering :: Greater ) ,
39
+ ( _, BaseHasVtable ) => Some ( cmp:: Ordering :: Less ) ,
40
+ ( SelfHasVtable , _) => Some ( cmp:: Ordering :: Greater ) ,
41
+ ( _, SelfHasVtable ) => Some ( cmp:: Ordering :: Less ) ,
42
+ _ => unreachable ! ( ) ,
43
+ }
44
+ }
45
+ }
46
+
47
+ impl HasVtableResult {
48
+ /// Take the least upper bound of `self` and `rhs`.
49
+ pub fn join ( self , rhs : Self ) -> Self {
50
+ cmp:: max ( self , rhs)
51
+ }
52
+ }
53
+
54
+ impl ops:: BitOr for HasVtableResult {
55
+ type Output = Self ;
56
+
57
+ fn bitor ( self , rhs : HasVtableResult ) -> Self :: Output {
58
+ self . join ( rhs)
59
+ }
60
+ }
61
+
62
+ impl ops:: BitOrAssign for HasVtableResult {
63
+ fn bitor_assign ( & mut self , rhs : HasVtableResult ) {
64
+ * self = self . join ( rhs)
65
+ }
66
+ }
9
67
10
68
/// An analysis that finds for each IR item whether it has vtable or not
11
69
///
@@ -23,7 +81,7 @@ pub struct HasVtableAnalysis<'ctx> {
23
81
24
82
// The incremental result of this analysis's computation. Everything in this
25
83
// set definitely has a vtable.
26
- have_vtable : HashSet < ItemId > ,
84
+ have_vtable : HashMap < ItemId , HasVtableResult > ,
27
85
28
86
// Dependencies saying that if a key ItemId has been inserted into the
29
87
// `have_vtable` set, then each of the ids in Vec<ItemId> need to be
@@ -47,26 +105,50 @@ impl<'ctx> HasVtableAnalysis<'ctx> {
47
105
}
48
106
}
49
107
50
- fn insert < Id : Into < ItemId > > ( & mut self , id : Id ) -> ConstrainResult {
108
+ fn insert < Id : Into < ItemId > > ( & mut self , id : Id , result : HasVtableResult ) -> ConstrainResult {
109
+ if let HasVtableResult :: No = result {
110
+ return ConstrainResult :: Same ;
111
+ }
112
+
51
113
let id = id. into ( ) ;
52
- let was_not_already_in_set = self . have_vtable . insert ( id) ;
53
- assert ! (
54
- was_not_already_in_set,
55
- "We shouldn't try and insert {:?} twice because if it was \
56
- already in the set, `constrain` should have exited early.",
57
- id
58
- ) ;
59
- ConstrainResult :: Changed
114
+ match self . have_vtable . entry ( id) {
115
+ Entry :: Occupied ( mut entry) => {
116
+ if * entry. get ( ) < result {
117
+ entry. insert ( result) ;
118
+ ConstrainResult :: Changed
119
+ } else {
120
+ ConstrainResult :: Same
121
+ }
122
+ }
123
+ Entry :: Vacant ( entry) => {
124
+ entry. insert ( result) ;
125
+ ConstrainResult :: Changed
126
+ }
127
+ }
128
+ }
129
+
130
+ fn forward < Id1 , Id2 > ( & mut self , from : Id1 , to : Id2 ) -> ConstrainResult
131
+ where
132
+ Id1 : Into < ItemId > ,
133
+ Id2 : Into < ItemId > ,
134
+ {
135
+ let from = from. into ( ) ;
136
+ let to = to. into ( ) ;
137
+
138
+ match self . have_vtable . get ( & from) . cloned ( ) {
139
+ None => ConstrainResult :: Same ,
140
+ Some ( r) => self . insert ( to, r) ,
141
+ }
60
142
}
61
143
}
62
144
63
145
impl < ' ctx > MonotoneFramework for HasVtableAnalysis < ' ctx > {
64
146
type Node = ItemId ;
65
147
type Extra = & ' ctx BindgenContext ;
66
- type Output = HashSet < ItemId > ;
148
+ type Output = HashMap < ItemId , HasVtableResult > ;
67
149
68
150
fn new ( ctx : & ' ctx BindgenContext ) -> HasVtableAnalysis < ' ctx > {
69
- let have_vtable = HashSet :: new ( ) ;
151
+ let have_vtable = HashMap :: new ( ) ;
70
152
let dependencies = generate_dependencies ( ctx, Self :: consider_edge) ;
71
153
72
154
HasVtableAnalysis {
@@ -81,11 +163,7 @@ impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
81
163
}
82
164
83
165
fn constrain ( & mut self , id : ItemId ) -> ConstrainResult {
84
- if self . have_vtable . contains ( & id) {
85
- // We've already computed that this type has a vtable and that can't
86
- // change.
87
- return ConstrainResult :: Same ;
88
- }
166
+ trace ! ( "constrain {:?}" , id) ;
89
167
90
168
let item = self . ctx . resolve_item ( id) ;
91
169
let ty = match item. as_type ( ) {
@@ -99,33 +177,32 @@ impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
99
177
TypeKind :: Alias ( t) |
100
178
TypeKind :: ResolvedTypeRef ( t) |
101
179
TypeKind :: Reference ( t) => {
102
- if self . have_vtable . contains ( & t. into ( ) ) {
103
- self . insert ( id)
104
- } else {
105
- ConstrainResult :: Same
106
- }
180
+ trace ! ( " aliases and references forward to their inner type" ) ;
181
+ self . forward ( t, id)
107
182
}
108
183
109
184
TypeKind :: Comp ( ref info) => {
185
+ trace ! ( " comp considers its own methods and bases" ) ;
186
+ let mut result = HasVtableResult :: No ;
187
+
110
188
if info. has_own_virtual_method ( ) {
111
- return self . insert ( id) ;
189
+ trace ! ( " comp has its own virtual method" ) ;
190
+ result |= HasVtableResult :: SelfHasVtable ;
112
191
}
192
+
113
193
let bases_has_vtable = info. base_members ( ) . iter ( ) . any ( |base| {
114
- self . have_vtable . contains ( & base. ty . into ( ) )
194
+ trace ! ( " comp has a base with a vtable: {:?}" , base) ;
195
+ self . have_vtable . contains_key ( & base. ty . into ( ) )
115
196
} ) ;
116
197
if bases_has_vtable {
117
- self . insert ( id)
118
- } else {
119
- ConstrainResult :: Same
198
+ result |= HasVtableResult :: BaseHasVtable ;
120
199
}
200
+
201
+ self . insert ( id, result)
121
202
}
122
203
123
204
TypeKind :: TemplateInstantiation ( ref inst) => {
124
- if self . have_vtable . contains ( & inst. template_definition ( ) . into ( ) ) {
125
- self . insert ( id)
126
- } else {
127
- ConstrainResult :: Same
128
- }
205
+ self . forward ( inst. template_definition ( ) , id)
129
206
}
130
207
131
208
_ => ConstrainResult :: Same ,
@@ -145,8 +222,13 @@ impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
145
222
}
146
223
}
147
224
148
- impl < ' ctx > From < HasVtableAnalysis < ' ctx > > for HashSet < ItemId > {
225
+ impl < ' ctx > From < HasVtableAnalysis < ' ctx > > for HashMap < ItemId , HasVtableResult > {
149
226
fn from ( analysis : HasVtableAnalysis < ' ctx > ) -> Self {
227
+ // We let the lack of an entry mean "No" to save space.
228
+ extra_assert ! ( analysis. have_vtable. values( ) . all( |v| {
229
+ * v != HasVtableResult :: No
230
+ } ) ) ;
231
+
150
232
analysis. have_vtable
151
233
}
152
234
}
@@ -160,4 +242,8 @@ impl<'ctx> From<HasVtableAnalysis<'ctx>> for HashSet<ItemId> {
160
242
pub trait HasVtable {
161
243
/// Return `true` if this thing has vtable, `false` otherwise.
162
244
fn has_vtable ( & self , ctx : & BindgenContext ) -> bool ;
245
+
246
+ /// Return `true` if this thing has an actual vtable pointer in itself, as
247
+ /// opposed to transitively in a base member.
248
+ fn has_vtable_ptr ( & self , ctx : & BindgenContext ) -> bool ;
163
249
}
0 commit comments