@@ -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,6 @@ 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
- }
89
166
90
167
let item = self . ctx . resolve_item ( id) ;
91
168
let ty = match item. as_type ( ) {
@@ -99,33 +176,28 @@ impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
99
176
TypeKind :: Alias ( t) |
100
177
TypeKind :: ResolvedTypeRef ( t) |
101
178
TypeKind :: Reference ( t) => {
102
- if self . have_vtable . contains ( & t. into ( ) ) {
103
- self . insert ( id)
104
- } else {
105
- ConstrainResult :: Same
106
- }
179
+ self . forward ( t, id)
107
180
}
108
181
109
182
TypeKind :: Comp ( ref info) => {
183
+ let mut result = HasVtableResult :: No ;
184
+
110
185
if info. has_own_virtual_method ( ) {
111
- return self . insert ( id ) ;
186
+ result |= HasVtableResult :: SelfHasVtable ;
112
187
}
188
+
113
189
let bases_has_vtable = info. base_members ( ) . iter ( ) . any ( |base| {
114
- self . have_vtable . contains ( & base. ty . into ( ) )
190
+ self . have_vtable . contains_key ( & base. ty . into ( ) )
115
191
} ) ;
116
192
if bases_has_vtable {
117
- self . insert ( id)
118
- } else {
119
- ConstrainResult :: Same
193
+ result |= HasVtableResult :: BaseHasVtable ;
120
194
}
195
+
196
+ self . insert ( id, result)
121
197
}
122
198
123
199
TypeKind :: TemplateInstantiation ( ref inst) => {
124
- if self . have_vtable . contains ( & inst. template_definition ( ) . into ( ) ) {
125
- self . insert ( id)
126
- } else {
127
- ConstrainResult :: Same
128
- }
200
+ self . forward ( inst. template_definition ( ) , id)
129
201
}
130
202
131
203
_ => ConstrainResult :: Same ,
@@ -145,8 +217,13 @@ impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
145
217
}
146
218
}
147
219
148
- impl < ' ctx > From < HasVtableAnalysis < ' ctx > > for HashSet < ItemId > {
220
+ impl < ' ctx > From < HasVtableAnalysis < ' ctx > > for HashMap < ItemId , HasVtableResult > {
149
221
fn from ( analysis : HasVtableAnalysis < ' ctx > ) -> Self {
222
+ // We let the lack of an entry mean "No" to save space.
223
+ extra_assert ! ( analysis. have_vtable. values( ) . all( |v| {
224
+ * v != HasVtableResult :: No
225
+ } ) ) ;
226
+
150
227
analysis. have_vtable
151
228
}
152
229
}
0 commit comments