Skip to content

Commit 397284c

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 c7b46f9 commit 397284c

File tree

1 file changed

+75
-29
lines changed

1 file changed

+75
-29
lines changed

src/java_bytecode/ci_lazy_methods.cpp

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -122,46 +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, virtual_function_calls);
154+
any_new_methods = true;
148155
}
149-
gather_virtual_callsites(
150-
symbol_table.lookup_ref(mname).value, virtual_function_calls);
151-
any_new_methods=true;
152156
}
153-
}
154157

155-
// Given the object types we now know may be created, populate more
156-
// possible virtual function call targets:
158+
// Given the object types we now know may be created, populate more
159+
// possible virtual function call targets:
157160

158-
debug() << "CI lazy methods: add virtual method targets ("
159-
<< virtual_function_calls.size() << " callsites)" << eom;
161+
debug() << "CI lazy methods: add virtual method targets ("
162+
<< virtual_function_calls.size() << " callsites)" << eom;
160163

161-
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)
162183
{
184+
id_sett candidate_target_methods;
163185
get_virtual_method_targets(
164-
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+
{
193+
any_new_classes = true;
194+
195+
// Add the call class to instantiated_classes and assert that it
196+
// didn't already exist
197+
const irep_idt &call_class = virtual_function_call.get(ID_C_class);
198+
auto ret_class = instantiated_classes.insert(call_class);
199+
CHECK_RETURN(ret_class.second);
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);
210+
}
165211
}
166212
}
167213

0 commit comments

Comments
 (0)