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