Skip to content

Commit b858e9a

Browse files
author
Owen Jones
committed
Deal with virtual function calls with no candidate targets
During virtual method resolution, if a virtual function call has no candidate targets then we add the class it was called on as an instantiated class.
1 parent 082d3f0 commit b858e9a

File tree

1 file changed

+72
-32
lines changed

1 file changed

+72
-32
lines changed

src/java_bytecode/ci_lazy_methods.cpp

+72-32
Original file line numberDiff line numberDiff line change
@@ -122,52 +122,92 @@ bool ci_lazy_methodst::operator()(
122122
id_sett methods_already_populated;
123123
std::unordered_set<exprt, irep_hash> virtual_function_calls;
124124

125-
bool any_new_methods=true;
126-
while(any_new_methods)
125+
bool any_new_classes = true;
126+
while(any_new_classes)
127127
{
128-
any_new_methods=false;
129-
while(!methods_to_convert_later.empty())
128+
bool any_new_methods=true;
129+
while(any_new_methods)
130130
{
131-
id_sett methods_to_convert;
132-
std::swap(methods_to_convert, methods_to_convert_later);
133-
for(const auto &mname : methods_to_convert)
131+
any_new_methods=false;
132+
while(!methods_to_convert_later.empty())
134133
{
135-
if(!methods_already_populated.insert(mname).second)
136-
continue;
137-
debug() << "CI lazy methods: elaborate " << mname << eom;
138-
if(
139-
method_converter(
140-
mname,
141-
// Note this wraps *references* to methods_to_convert_later &
142-
// instantiated_classes
143-
ci_lazy_methods_neededt(
144-
methods_to_convert_later, instantiated_classes, symbol_table)))
134+
id_sett methods_to_convert;
135+
std::swap(methods_to_convert, methods_to_convert_later);
136+
for(const auto &mname : methods_to_convert)
145137
{
146-
// Couldn't convert this function
147-
continue;
138+
if(!methods_already_populated.insert(mname).second)
139+
continue;
140+
debug() << "CI lazy methods: elaborate " << mname << eom;
141+
if(
142+
method_converter(
143+
mname,
144+
// Note this wraps *references* to methods_to_convert_later &
145+
// instantiated_classes
146+
ci_lazy_methods_neededt(
147+
methods_to_convert_later, instantiated_classes, symbol_table)))
148+
{
149+
// Couldn't convert this function
150+
continue;
151+
}
152+
gather_virtual_callsites(
153+
symbol_table.lookup_ref(mname).value,
154+
virtual_function_calls);
155+
any_new_methods=true;
148156
}
149-
gather_virtual_callsites(
150-
symbol_table.lookup_ref(mname).value,
151-
virtual_function_calls);
152-
any_new_methods=true;
153157
}
154-
}
155158

156-
// Given the object types we now know may be created, populate more
157-
// possible virtual function call targets:
159+
// Given the object types we now know may be created, populate more
160+
// possible virtual function call targets:
161+
162+
debug() << "CI lazy methods: add virtual method targets ("
163+
<< virtual_function_calls.size()
164+
<< " callsites)"
165+
<< eom;
166+
167+
for(const exprt &function : virtual_function_calls)
168+
{
169+
get_virtual_method_targets(
170+
function, instantiated_classes, methods_to_convert_later, symbol_table);
171+
}
172+
}
158173

159-
debug() << "CI lazy methods: add virtual method targets ("
160-
<< virtual_function_calls.size()
161-
<< " callsites)"
162-
<< eom;
174+
any_new_classes = false;
163175

164-
for(const exprt &function : virtual_function_calls)
176+
// Find virtual callsites with no candidate targets, guess that the class
177+
// must be instantiated, and create a stub method if needed
178+
for(const exprt &virtual_function_call : virtual_function_calls)
165179
{
180+
id_sett candidate_target_methods;
166181
get_virtual_method_targets(
167-
function, instantiated_classes, methods_to_convert_later, symbol_table);
182+
virtual_function_call,
183+
instantiated_classes,
184+
candidate_target_methods,
185+
symbol_table);
186+
187+
if(candidate_target_methods.empty())
188+
{
189+
any_new_classes = true;
190+
191+
// Add the call class to instantiated_classes and assert that it
192+
// didn't already exist
193+
const irep_idt &call_class = virtual_function_call.get(ID_C_class);
194+
auto ret_class = instantiated_classes.insert(call_class);
195+
CHECK_RETURN(ret_class.second);
196+
197+
// Check that `get_virtual_method_target` returns a method now
198+
const irep_idt &call_basename =
199+
virtual_function_call.get(ID_component_name);
200+
const irep_idt method_name = get_virtual_method_target(
201+
instantiated_classes, call_basename, call_class, symbol_table);
202+
CHECK_RETURN(!method_name.empty());
203+
204+
// Add what it returns to methods_to_convert_later
205+
methods_to_convert_later.insert(method_name);
206+
}
168207
}
169208
}
170209

210+
171211
// Remove symbols for methods that were declared but never used:
172212
symbol_tablet keep_symbols;
173213
// Manually keep @inflight_exception, as it is unused at this stage

0 commit comments

Comments
 (0)