@@ -30,6 +30,12 @@ class remove_virtual_functionst
30
30
31
31
bool remove_virtual_functions (goto_programt &goto_program);
32
32
33
+ void remove_virtual_function (
34
+ goto_programt &goto_program,
35
+ goto_programt::targett target,
36
+ const dispatch_table_entriest &functions,
37
+ virtual_dispatch_fallback_actiont fallback_action);
38
+
33
39
protected:
34
40
const namespacet ns;
35
41
const symbol_tablet &symbol_table;
@@ -40,25 +46,12 @@ class remove_virtual_functionst
40
46
goto_programt &goto_program,
41
47
goto_programt::targett target);
42
48
43
- class functiont
44
- {
45
- public:
46
- functiont () {}
47
- explicit functiont (const irep_idt &_class_id) :
48
- class_id(_class_id)
49
- {}
50
-
51
- symbol_exprt symbol_expr;
52
- irep_idt class_id;
53
- };
54
-
55
- typedef std::vector<functiont> functionst;
56
- void get_functions (const exprt &, functionst &);
49
+ void get_functions (const exprt &, dispatch_table_entriest &);
57
50
void get_child_functions_rec (
58
51
const irep_idt &,
59
52
const symbol_exprt &,
60
53
const irep_idt &,
61
- functionst &,
54
+ dispatch_table_entriest &,
62
55
std::set<irep_idt> &visited) const ;
63
56
exprt get_method (
64
57
const irep_idt &class_id,
@@ -81,25 +74,46 @@ void remove_virtual_functionst::remove_virtual_function(
81
74
const code_function_callt &code=
82
75
to_code_function_call (target->code );
83
76
84
- const auto &vcall_source_loc=target->source_location ;
85
-
86
77
const exprt &function=code.function ();
87
- assert (function.id ()==ID_virtual_function);
88
- assert (!code.arguments ().empty ());
89
-
90
- functionst functions;
78
+ INVARIANT (
79
+ function.id ()==ID_virtual_function,
80
+ " remove_virtual_function must take a virtual function call instruction" );
81
+ INVARIANT (
82
+ !code.arguments ().empty (),
83
+ " virtual function calls must have at least a this-argument" );
84
+
85
+ dispatch_table_entriest functions;
91
86
get_functions (function, functions);
92
87
88
+ remove_virtual_function (
89
+ goto_program,
90
+ target,
91
+ functions,
92
+ virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION);
93
+ }
94
+
95
+ void remove_virtual_functionst::remove_virtual_function (
96
+ goto_programt &goto_program,
97
+ goto_programt::targett target,
98
+ const dispatch_table_entriest &functions,
99
+ virtual_dispatch_fallback_actiont fallback_action)
100
+ {
101
+ INVARIANT (
102
+ target->is_function_call (),
103
+ " remove_virtual_function must target a FUNCTION_CALL instruction" );
104
+ const code_function_callt &code=
105
+ to_code_function_call (target->code );
106
+
93
107
if (functions.empty ())
94
108
{
95
109
target->make_skip ();
96
110
return ; // give up
97
111
}
98
112
99
113
// only one option?
100
- if (functions.size ()==1 )
114
+ if (functions.size ()==1 &&
115
+ fallback_action==virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION)
101
116
{
102
- assert (target->is_function_call ());
103
117
if (functions.begin ()->symbol_expr ==symbol_exprt ())
104
118
target->make_skip ();
105
119
else
@@ -108,6 +122,8 @@ void remove_virtual_functionst::remove_virtual_function(
108
122
return ;
109
123
}
110
124
125
+ const auto &vcall_source_loc=target->source_location ;
126
+
111
127
// the final target is a skip
112
128
goto_programt final_skip;
113
129
@@ -122,16 +138,29 @@ void remove_virtual_functionst::remove_virtual_function(
122
138
goto_programt new_code_gotos;
123
139
124
140
exprt this_expr=code.arguments ()[0 ];
125
- // If necessary, cast to the last candidate function to
126
- // get the object's clsid. By the structure of get_functions,
127
- // this is the parent of all other classes under consideration.
128
- const auto &base_classid=functions.back ().class_id ;
129
- const auto &base_function_symbol=functions.back ().symbol_expr ;
130
- symbol_typet suggested_type (base_classid);
131
- exprt c_id2=get_class_identifier_field (this_expr, suggested_type, ns);
141
+ const auto &last_function_symbol=functions.back ().symbol_expr ;
142
+
143
+ const typet &this_type=this_expr.type ();
144
+ INVARIANT (this_type.id () == ID_pointer, " this parameter must be a pointer" );
145
+ INVARIANT (
146
+ this_type.subtype () != empty_typet (),
147
+ " this parameter must not be a void pointer" );
148
+
149
+ // So long as `this` is already not `void*` typed, the second parameter
150
+ // is ignored:
151
+ exprt c_id2=get_class_identifier_field (this_expr, symbol_typet (), ns);
152
+
153
+ // If instructed, add an ASSUME(FALSE) to handle the case where we don't
154
+ // match any expected type:
155
+ if (fallback_action==virtual_dispatch_fallback_actiont::ASSUME_FALSE)
156
+ {
157
+ auto newinst=new_code_calls.add_instruction (ASSUME);
158
+ newinst->guard =false_exprt ();
159
+ newinst->source_location =vcall_source_loc;
160
+ }
132
161
133
162
std::map<irep_idt, goto_programt::targett> calls;
134
- // Note backwards iteration, to get the least-derived candidate first.
163
+ // Note backwards iteration, to get the fallback candidate first.
135
164
for (auto it=functions.crbegin (), itend=functions.crend (); it!=itend; ++it)
136
165
{
137
166
const auto &fun=*it;
@@ -149,8 +178,13 @@ void remove_virtual_functionst::remove_virtual_function(
149
178
t1->make_function_call (code);
150
179
auto &newcall=to_code_function_call (t1->code );
151
180
newcall.function ()=fun.symbol_expr ;
152
- typet need_type=
153
- pointer_type (symbol_typet (fun.symbol_expr .get (ID_C_class)));
181
+ // Cast the `this` pointer to the correct type for the new callee:
182
+ const auto &callee_type=
183
+ to_code_type (ns.lookup (fun.symbol_expr .get_identifier ()).type );
184
+ INVARIANT (
185
+ callee_type.has_this (),
186
+ " Virtual function callees must have a `this` argument" );
187
+ typet need_type=callee_type.parameters ()[0 ].type ();
154
188
if (!type_eq (newcall.arguments ()[0 ].type (), need_type, ns))
155
189
newcall.arguments ()[0 ].make_typecast (need_type);
156
190
}
@@ -166,9 +200,10 @@ void remove_virtual_functionst::remove_virtual_function(
166
200
t3->make_goto (t_final, true_exprt ());
167
201
}
168
202
169
- // If this calls the base function we just fall through.
203
+ // If this calls the fallback function we just fall through.
170
204
// Otherwise branch to the right call:
171
- if (fun.symbol_expr !=base_function_symbol)
205
+ if (fallback_action!=virtual_dispatch_fallback_actiont::CALL_LAST_FUNCTION ||
206
+ fun.symbol_expr !=last_function_symbol)
172
207
{
173
208
exprt c_id1=constant_exprt (fun.class_id , string_typet ());
174
209
goto_programt::targett t4=new_code_gotos.add_instruction ();
@@ -221,7 +256,7 @@ void remove_virtual_functionst::get_child_functions_rec(
221
256
const irep_idt &this_id,
222
257
const symbol_exprt &last_method_defn,
223
258
const irep_idt &component_name,
224
- functionst &functions,
259
+ dispatch_table_entriest &functions,
225
260
std::set<irep_idt> &visited) const
226
261
{
227
262
auto findit=class_hierarchy.class_map .find (this_id);
@@ -233,7 +268,7 @@ void remove_virtual_functionst::get_child_functions_rec(
233
268
if (!visited.insert (child).second )
234
269
continue ;
235
270
exprt method=get_method (child, component_name);
236
- functiont function (child);
271
+ dispatch_table_entryt function (child);
237
272
if (method.is_not_nil ())
238
273
{
239
274
function.symbol_expr =to_symbol_expr (method);
@@ -256,7 +291,7 @@ void remove_virtual_functionst::get_child_functions_rec(
256
291
257
292
void remove_virtual_functionst::get_functions (
258
293
const exprt &function,
259
- functionst &functions)
294
+ dispatch_table_entriest &functions)
260
295
{
261
296
const irep_idt class_id=function.get (ID_C_class);
262
297
const irep_idt component_name=function.get (ID_component_name);
@@ -266,7 +301,7 @@ void remove_virtual_functionst::get_functions(
266
301
symbol_table, class_hierarchy);
267
302
const resolve_concrete_function_callt::concrete_function_callt &
268
303
resolved_call=get_virtual_call_target (class_id, component_name);
269
- functiont root_function;
304
+ dispatch_table_entryt root_function;
270
305
271
306
if (resolved_call.is_valid ())
272
307
{
@@ -373,3 +408,17 @@ void remove_virtual_functions(goto_modelt &goto_model)
373
408
remove_virtual_functions (
374
409
goto_model.symbol_table , goto_model.goto_functions );
375
410
}
411
+
412
+ void remove_virtual_function (
413
+ goto_modelt &goto_model,
414
+ goto_programt &goto_program,
415
+ goto_programt::targett instruction,
416
+ const dispatch_table_entriest &dispatch_table,
417
+ virtual_dispatch_fallback_actiont fallback_action)
418
+ {
419
+ remove_virtual_functionst
420
+ rvf (goto_model.symbol_table , goto_model.goto_functions );
421
+
422
+ rvf.remove_virtual_function (
423
+ goto_program, instruction, dispatch_table, fallback_action);
424
+ }
0 commit comments