@@ -123,7 +123,9 @@ bool ci_lazy_methodst::operator()(
123
123
std::unordered_set<irep_idt> methods_already_populated;
124
124
std::unordered_set<exprt, irep_hash> virtual_function_calls;
125
125
126
- bool any_new_methods = true ;
126
+ bool any_new_classes = true ;
127
+ while (any_new_classes)
128
+ {bool any_new_methods = true ;
127
129
while (any_new_methods)
128
130
{
129
131
any_new_methods=false ;
@@ -153,16 +155,58 @@ bool ci_lazy_methodst::operator()(
153
155
}
154
156
}
155
157
156
- // Given the object types we now know may be created, populate more
157
- // possible virtual function call targets:
158
+ // Given the object types we now know may be created, populate more
159
+ // possible virtual function call targets:
158
160
159
- debug () << " CI lazy methods: add virtual method targets ("
160
- << virtual_function_calls.size () << " callsites)" << eom;
161
+ debug () << " CI lazy methods: add virtual method targets ("
162
+ << virtual_function_calls.size () << " callsites)" << eom;
161
163
162
- for (const exprt &function : virtual_function_calls)
164
+ for (const exprt &function : virtual_function_calls)
165
+ {
166
+ get_virtual_method_targets (
167
+ function,
168
+ instantiated_classes,
169
+ methods_to_convert_later,
170
+ symbol_table);
171
+ }
172
+ }
173
+
174
+ any_new_classes = false ;
175
+
176
+ // Look for virtual callsites with no candidate targets. If we have
177
+ // invokevirtual A.f and we don't believe either A or any of its children
178
+ // may exist, we assume specifically A is somehow instantiated. Note this
179
+ // may result in an abstract class being classified as instantiated, which
180
+ // stands in for some unknown concrete subclass: in this case the called
181
+ // method will be a stub.
182
+ for (const exprt &virtual_function_call : virtual_function_calls)
163
183
{
184
+ std::unordered_set<irep_idt> candidate_target_methods;
164
185
get_virtual_method_targets (
165
- function, instantiated_classes, methods_to_convert_later, symbol_table);
186
+ virtual_function_call,
187
+ instantiated_classes,
188
+ candidate_target_methods,
189
+ symbol_table);
190
+
191
+ if (!candidate_target_methods.empty ())
192
+ continue ;
193
+
194
+ // Add the call class to instantiated_classes and assert that it
195
+ // didn't already exist
196
+ const irep_idt &call_class = virtual_function_call.get (ID_C_class);
197
+ auto ret_class = instantiated_classes.insert (call_class);
198
+ CHECK_RETURN (ret_class.second );
199
+ any_new_classes = true ;
200
+
201
+ // Check that `get_virtual_method_target` returns a method now
202
+ const irep_idt &call_basename =
203
+ virtual_function_call.get (ID_component_name);
204
+ const irep_idt method_name = get_virtual_method_target (
205
+ instantiated_classes, call_basename, call_class, symbol_table);
206
+ CHECK_RETURN (!method_name.empty ());
207
+
208
+ // Add what it returns to methods_to_convert_later
209
+ methods_to_convert_later.insert (method_name);
166
210
}
167
211
}
168
212
0 commit comments