@@ -178,7 +178,8 @@ void remove_virtual_functionst::remove_virtual_function(
178
178
179
179
// So long as `this` is already not `void*` typed, the second parameter
180
180
// is ignored:
181
- exprt c_id2=get_class_identifier_field (this_expr, symbol_typet (), ns);
181
+ exprt this_class_identifier =
182
+ get_class_identifier_field (this_expr, symbol_typet (), ns);
182
183
183
184
// If instructed, add an ASSUME(FALSE) to handle the case where we don't
184
185
// match any expected type:
@@ -191,16 +192,12 @@ void remove_virtual_functionst::remove_virtual_function(
191
192
192
193
// get initial identifier for grouping
193
194
INVARIANT (!functions.empty (), " Function dispatch table cannot be empty." );
194
- auto last_id = functions.back ().symbol_expr .get_identifier ();
195
- // record class_ids for disjunction
196
- std::set<irep_idt> class_ids;
197
195
198
196
std::map<irep_idt, goto_programt::targett> calls;
199
197
// Note backwards iteration, to get the fallback candidate first.
200
198
for (auto it=functions.crbegin (), itend=functions.crend (); it!=itend; ++it)
201
199
{
202
200
const auto &fun=*it;
203
- class_ids.insert (fun.class_id );
204
201
auto insertit=calls.insert (
205
202
{fun.symbol_expr .get_identifier (), goto_programt::targett ()});
206
203
@@ -232,49 +229,36 @@ void remove_virtual_functionst::remove_virtual_function(
232
229
t3->make_goto (t_final, true_exprt ());
233
230
}
234
231
235
- // Emit target if end of dispatch table is reached or if the next element is
236
- // dispatched to another function call. Assumes entries in the functions
237
- // variable to be sorted for the identifier of the function to be called.
238
- auto l_it = std::next (it);
239
- bool next_emit_target =
240
- (l_it == functions.crend ()) ||
241
- l_it->symbol_expr .get_identifier () != fun.symbol_expr .get_identifier ();
242
-
243
- // The root function call is done via fall-through, so nothing to emit
244
- // explicitly for this.
245
- if (next_emit_target && fun.symbol_expr == last_function_symbol)
232
+ // Fall through to the default callee if possible:
233
+ if (fallback_action ==
234
+ virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION &&
235
+ fun.symbol_expr == last_function_symbol)
246
236
{
247
- class_ids. clear ();
237
+ // Nothing to do
248
238
}
249
-
250
- // If this calls the fallback function we just fall through.
251
- // Otherwise branch to the right call:
252
- if (fallback_action!=virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION ||
253
- fun.symbol_expr !=last_function_symbol)
239
+ else
254
240
{
255
- // create a disjunction of class_ids to test
256
- if (next_emit_target && fun.symbol_expr != last_function_symbol)
241
+ const constant_exprt fun_class_identifier (fun.class_id , string_typet ());
242
+ const equal_exprt class_id_test (
243
+ fun_class_identifier, this_class_identifier);
244
+
245
+ // If the previous GOTO goes to the same callee, join it
246
+ // (e.g. turning IF x GOTO y into IF x || z GOTO y)
247
+ if (it != functions.crbegin () &&
248
+ std::prev (it)->symbol_expr == fun.symbol_expr )
257
249
{
258
- exprt::operandst or_ops;
259
- for (const auto &id : class_ids)
260
- {
261
- const constant_exprt c_id1 (id, string_typet ());
262
- const equal_exprt class_id_test (c_id1, c_id2);
263
- or_ops.push_back (class_id_test);
264
- }
265
-
266
- goto_programt::targett t4 = new_code_gotos.add_instruction ();
267
- t4->source_location = vcall_source_loc;
268
- t4->make_goto (insertit.first ->second , disjunction (or_ops));
269
-
270
- last_id = fun.symbol_expr .get_identifier ();
271
- class_ids.clear ();
250
+ INVARIANT (
251
+ !new_code_gotos.empty (),
252
+ " a dispatch table entry has been processed already, "
253
+ " which should have created a GOTO" );
254
+ new_code_gotos.instructions .back ().guard =
255
+ or_exprt (new_code_gotos.instructions .back ().guard , class_id_test);
272
256
}
273
- // record class_id
274
- else if (next_emit_target)
257
+ else
275
258
{
276
- last_id = fun.symbol_expr .get_identifier ();
277
- class_ids.clear ();
259
+ goto_programt::targett new_goto = new_code_gotos.add_instruction ();
260
+ new_goto->source_location = vcall_source_loc;
261
+ new_goto->make_goto (insertit.first ->second , class_id_test);
278
262
}
279
263
}
280
264
}
@@ -555,20 +539,35 @@ void remove_virtual_functions(goto_model_functiont &function)
555
539
}
556
540
557
541
void remove_virtual_function (
558
- goto_modelt &goto_model ,
542
+ symbol_tablet &symbol_table ,
559
543
goto_programt &goto_program,
560
544
goto_programt::targett instruction,
561
545
const dispatch_table_entriest &dispatch_table,
562
546
virtual_dispatch_fallback_actiont fallback_action)
563
547
{
564
548
class_hierarchyt class_hierarchy;
565
- class_hierarchy (goto_model. symbol_table );
566
- remove_virtual_functionst rvf (goto_model. symbol_table , class_hierarchy);
549
+ class_hierarchy (symbol_table);
550
+ remove_virtual_functionst rvf (symbol_table, class_hierarchy);
567
551
568
552
rvf.remove_virtual_function (
569
553
goto_program, instruction, dispatch_table, fallback_action);
570
554
}
571
555
556
+ void remove_virtual_function (
557
+ goto_modelt &goto_model,
558
+ goto_programt &goto_program,
559
+ goto_programt::targett instruction,
560
+ const dispatch_table_entriest &dispatch_table,
561
+ virtual_dispatch_fallback_actiont fallback_action)
562
+ {
563
+ remove_virtual_function (
564
+ goto_model.symbol_table ,
565
+ goto_program,
566
+ instruction,
567
+ dispatch_table,
568
+ fallback_action);
569
+ }
570
+
572
571
void collect_virtual_function_callees (
573
572
const exprt &function,
574
573
const symbol_table_baset &symbol_table,
0 commit comments