Skip to content

Commit 4259189

Browse files
Merge pull request #5007 from owen-mc-diffblue/virtual-function-expr
Create class_method_descriptor_exprt for ID_virtual_function
2 parents cd54630 + f2643b3 commit 4259189

File tree

10 files changed

+143
-68
lines changed

10 files changed

+143
-68
lines changed

jbmc/src/java_bytecode/ci_lazy_methods.cpp

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ bool ci_lazy_methodst::operator()(
130130
}
131131

132132
std::unordered_set<irep_idt> methods_already_populated;
133-
std::unordered_set<exprt, irep_hash> virtual_function_calls;
133+
std::unordered_set<class_method_descriptor_exprt, irep_hash>
134+
called_virtual_functions;
134135
bool class_initializer_seen = false;
135136

136137
bool any_new_classes = true;
@@ -154,7 +155,7 @@ bool ci_lazy_methodst::operator()(
154155
symbol_table,
155156
methods_to_convert_later,
156157
instantiated_classes,
157-
virtual_function_calls);
158+
called_virtual_functions);
158159
any_new_methods |= conversion_result.new_method_seen;
159160
class_initializer_seen |= conversion_result.class_initializer_seen;
160161
}
@@ -164,12 +165,13 @@ bool ci_lazy_methodst::operator()(
164165
// possible virtual function call targets:
165166

166167
debug() << "CI lazy methods: add virtual method targets ("
167-
<< virtual_function_calls.size() << " callsites)" << eom;
168+
<< called_virtual_functions.size() << " callsites)" << eom;
168169

169-
for(const exprt &function : virtual_function_calls)
170+
for(const class_method_descriptor_exprt &called_virtual_function :
171+
called_virtual_functions)
170172
{
171173
get_virtual_method_targets(
172-
function,
174+
called_virtual_function,
173175
instantiated_classes,
174176
methods_to_convert_later,
175177
symbol_table);
@@ -179,7 +181,7 @@ bool ci_lazy_methodst::operator()(
179181
any_new_classes = handle_virtual_methods_with_no_callees(
180182
methods_to_convert_later,
181183
instantiated_classes,
182-
virtual_function_calls,
184+
called_virtual_functions,
183185
symbol_table);
184186
}
185187

@@ -231,7 +233,8 @@ bool ci_lazy_methodst::operator()(
231233
bool ci_lazy_methodst::handle_virtual_methods_with_no_callees(
232234
std::unordered_set<irep_idt> &methods_to_convert_later,
233235
std::unordered_set<irep_idt> &instantiated_classes,
234-
const std::unordered_set<exprt, irep_hash> &virtual_function_calls,
236+
const std::unordered_set<class_method_descriptor_exprt, irep_hash>
237+
&virtual_functions,
235238
symbol_tablet &symbol_table)
236239
{
237240
ci_lazy_methods_neededt lazy_methods_loader(
@@ -241,11 +244,11 @@ bool ci_lazy_methodst::handle_virtual_methods_with_no_callees(
241244
pointer_type_selector);
242245

243246
bool any_new_classes = false;
244-
for(const exprt &virtual_function_call : virtual_function_calls)
247+
for(const class_method_descriptor_exprt &virtual_function : virtual_functions)
245248
{
246249
std::unordered_set<irep_idt> candidate_target_methods;
247250
get_virtual_method_targets(
248-
virtual_function_call,
251+
virtual_function,
249252
instantiated_classes,
250253
candidate_target_methods,
251254
symbol_table);
@@ -254,13 +257,13 @@ bool ci_lazy_methodst::handle_virtual_methods_with_no_callees(
254257
continue;
255258

256259
const java_method_typet &java_method_type =
257-
to_java_method_type(virtual_function_call.type());
260+
to_java_method_type(virtual_function.type());
258261

259262
// Add the call class to instantiated_classes and assert that it
260263
// didn't already exist. It can't be instantiated already, otherwise it
261264
// would give a concrete definition of the called method, and
262265
// candidate_target_methods would be non-empty.
263-
const irep_idt &call_class = virtual_function_call.get(ID_C_class);
266+
const irep_idt &call_class = virtual_function.get_class_name();
264267
bool was_missing = instantiated_classes.count(call_class) == 0;
265268
CHECK_RETURN(was_missing);
266269
any_new_classes = true;
@@ -289,8 +292,7 @@ bool ci_lazy_methodst::handle_virtual_methods_with_no_callees(
289292
}
290293

291294
// Check that `get_virtual_method_target` returns a method now
292-
const irep_idt &call_basename =
293-
virtual_function_call.get(ID_component_name);
295+
const irep_idt &call_basename = virtual_function.get_component_name();
294296
const irep_idt method_name = get_virtual_method_target(
295297
instantiated_classes, call_basename, call_class, symbol_table);
296298
CHECK_RETURN(!method_name.empty());
@@ -303,7 +305,7 @@ bool ci_lazy_methodst::handle_virtual_methods_with_no_callees(
303305

304306
/// Convert a method, add it to the populated set, add needed methods to
305307
/// methods_to_convert_later and add virtual calls from the method to
306-
/// virtual_function_calls
308+
/// virtual_functions
307309
/// \return structure containing two Booleans:
308310
/// * class_initializer_seen which is true if the class_initializer_seen
309311
/// argument was false and the class_model is referenced in
@@ -319,7 +321,8 @@ ci_lazy_methodst::convert_and_analyze_method(
319321
symbol_tablet &symbol_table,
320322
std::unordered_set<irep_idt> &methods_to_convert_later,
321323
std::unordered_set<irep_idt> &instantiated_classes,
322-
std::unordered_set<exprt, irep_hash> &virtual_function_calls)
324+
std::unordered_set<class_method_descriptor_exprt, irep_hash>
325+
&called_virtual_functions)
323326
{
324327
convert_method_resultt result;
325328
if(!methods_already_populated.insert(method_name).second)
@@ -339,7 +342,7 @@ ci_lazy_methodst::convert_and_analyze_method(
339342
return result;
340343

341344
const exprt &method_body = symbol_table.lookup_ref(method_name).value;
342-
gather_virtual_callsites(method_body, virtual_function_calls);
345+
gather_virtual_callsites(method_body, called_virtual_functions);
343346

344347
if(!class_initializer_already_seen && references_class_model(method_body))
345348
{
@@ -438,15 +441,18 @@ void ci_lazy_methodst::initialize_instantiated_classes(
438441
/// e that calls a virtual function.
439442
void ci_lazy_methodst::gather_virtual_callsites(
440443
const exprt &e,
441-
std::unordered_set<exprt, irep_hash> &result)
444+
std::unordered_set<class_method_descriptor_exprt, irep_hash> &result)
442445
{
443446
if(e.id()!=ID_code)
444447
return;
445448
const codet &c=to_code(e);
446-
if(c.get_statement()==ID_function_call &&
447-
to_code_function_call(c).function().id()==ID_virtual_function)
449+
if(
450+
c.get_statement() == ID_function_call &&
451+
can_cast_expr<class_method_descriptor_exprt>(
452+
to_code_function_call(c).function()))
448453
{
449-
result.insert(to_code_function_call(c).function());
454+
result.insert(
455+
to_class_method_descriptor_expr(to_code_function_call(c).function()));
450456
}
451457
else
452458
{
@@ -466,17 +472,15 @@ void ci_lazy_methodst::gather_virtual_callsites(
466472
/// defined on classes that are not 'needed' are ignored)
467473
/// \param symbol_table: global symbol table
468474
void ci_lazy_methodst::get_virtual_method_targets(
469-
const exprt &called_function,
475+
const class_method_descriptor_exprt &called_function,
470476
const std::unordered_set<irep_idt> &instantiated_classes,
471477
std::unordered_set<irep_idt> &callable_methods,
472478
symbol_tablet &symbol_table)
473479
{
474-
PRECONDITION(called_function.id()==ID_virtual_function);
475-
476-
const auto &call_class=called_function.get(ID_C_class);
480+
const auto &call_class = called_function.get_class_name();
477481
INVARIANT(
478482
!call_class.empty(), "All virtual calls should be aimed at a class");
479-
const auto &call_basename=called_function.get(ID_component_name);
483+
const auto &call_basename = called_function.get_component_name();
480484
INVARIANT(
481485
!call_basename.empty(),
482486
"Virtual function must have a reasonable name after removing class");

jbmc/src/java_bytecode/ci_lazy_methods.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ class ci_lazy_methodst:public messaget
122122

123123
void gather_virtual_callsites(
124124
const exprt &e,
125-
std::unordered_set<exprt, irep_hash> &result);
125+
std::unordered_set<class_method_descriptor_exprt, irep_hash> &result);
126126

127127
void get_virtual_method_targets(
128-
const exprt &called_function,
128+
const class_method_descriptor_exprt &called_function,
129129
const std::unordered_set<irep_idt> &instantiated_classes,
130130
std::unordered_set<irep_idt> &callable_methods,
131131
symbol_tablet &symbol_table);
@@ -171,12 +171,14 @@ class ci_lazy_methodst:public messaget
171171
symbol_tablet &symbol_table,
172172
std::unordered_set<irep_idt> &methods_to_convert_later,
173173
std::unordered_set<irep_idt> &instantiated_classes,
174-
std::unordered_set<exprt, irep_hash> &virtual_function_calls);
174+
std::unordered_set<class_method_descriptor_exprt, irep_hash>
175+
&called_virtual_functions);
175176

176177
bool handle_virtual_methods_with_no_callees(
177178
std::unordered_set<irep_idt> &methods_to_convert_later,
178179
std::unordered_set<irep_idt> &instantiated_classes,
179-
const std::unordered_set<exprt, irep_hash> &virtual_function_calls,
180+
const std::unordered_set<class_method_descriptor_exprt, irep_hash>
181+
&virtual_functions,
180182
symbol_tablet &symbol_table);
181183
};
182184

jbmc/src/java_bytecode/expr2java.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,11 @@ std::string expr2javat::convert_with_precedence(
420420
return "pod_constructor";
421421
else if(src.id()==ID_virtual_function)
422422
{
423-
return "VIRTUAL_FUNCTION(" +
424-
id2string(src.get(ID_C_class)) +
425-
"." +
426-
id2string(src.get(ID_component_name)) +
427-
")";
423+
const class_method_descriptor_exprt &virtual_function =
424+
to_class_method_descriptor_expr(src);
425+
return "CLASS_METHOD_DESCRIPTOR(" +
426+
id2string(virtual_function.get_class_name()) + "." +
427+
id2string(virtual_function.get_component_name()) + ")";
428428
}
429429
else if(
430430
const auto &literal = expr_try_dynamic_cast<java_string_literal_exprt>(src))

jbmc/src/java_bytecode/java_bytecode_convert_method.cpp

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,7 +1330,16 @@ java_bytecode_convert_methodt::convert_instructions(const methodt &method)
13301330
bytecode == BC_invokeinterface || bytecode == BC_invokespecial ||
13311331
bytecode == BC_invokevirtual || bytecode == BC_invokestatic)
13321332
{
1333-
convert_invoke(i_it->source_location, statement, arg0, c, results);
1333+
class_method_descriptor_exprt *class_method_descriptor =
1334+
expr_try_dynamic_cast<class_method_descriptor_exprt>(arg0);
1335+
1336+
INVARIANT(
1337+
class_method_descriptor,
1338+
"invokeinterface, invokespecial, invokevirtual and invokestatic should "
1339+
"be called with a class method descriptor expression as arg0");
1340+
1341+
convert_invoke(
1342+
i_it->source_location, statement, *class_method_descriptor, c, results);
13341343
}
13351344
else if(bytecode == BC_return)
13361345
{
@@ -2153,15 +2162,15 @@ static void adjust_invoke_argument_types(
21532162
void java_bytecode_convert_methodt::convert_invoke(
21542163
source_locationt location,
21552164
const irep_idt &statement,
2156-
exprt &arg0,
2165+
class_method_descriptor_exprt &class_method_descriptor,
21572166
codet &c,
21582167
exprt::operandst &results)
21592168
{
21602169
const bool use_this(statement != "invokestatic");
21612170
const bool is_virtual(
21622171
statement == "invokevirtual" || statement == "invokeinterface");
21632172

2164-
const irep_idt &invoked_method_id = arg0.get(ID_identifier);
2173+
const irep_idt &invoked_method_id = class_method_descriptor.get_identifier();
21652174
INVARIANT(
21662175
!invoked_method_id.empty(),
21672176
"invoke statement arg0 must have an identifier");
@@ -2177,21 +2186,22 @@ void java_bytecode_convert_methodt::convert_invoke(
21772186
// invokespecial will have zero arguments (the `this` is added below)
21782187
// but the symbol for the <init> will have the this parameter.
21792188
INVARIANT(
2180-
to_java_method_type(arg0.type()).return_type().id() ==
2189+
to_java_method_type(class_method_descriptor.type()).return_type().id() ==
21812190
to_code_type(method_symbol->second.type).return_type().id(),
21822191
"Function return type must not change in kind");
2183-
arg0.type() = method_symbol->second.type;
2192+
class_method_descriptor.type() = method_symbol->second.type;
21842193
}
21852194

21862195
// Note arg0 and arg0.type() are subject to many side-effects in this method,
21872196
// then finally used to populate the call instruction.
2188-
java_method_typet &method_type = to_java_method_type(arg0.type());
2197+
java_method_typet &method_type =
2198+
to_java_method_type(class_method_descriptor.type());
21892199

21902200
java_method_typet::parameterst &parameters(method_type.parameters());
21912201

21922202
if(use_this)
21932203
{
2194-
irep_idt classname = arg0.get(ID_C_class);
2204+
irep_idt classname = class_method_descriptor.get(ID_C_class);
21952205

21962206
if(parameters.empty() || !parameters[0].get_this())
21972207
{
@@ -2242,8 +2252,6 @@ void java_bytecode_convert_methodt::convert_invoke(
22422252
results[0] = promoted;
22432253
}
22442254

2245-
assert(arg0.id() == ID_virtual_function);
2246-
22472255
// If we don't have a definition for the called symbol, and we won't
22482256
// inherit a definition from a super-class, we create a new symbol and
22492257
// insert it in the symbol table. The name and type of the method are
@@ -2258,16 +2266,17 @@ void java_bytecode_convert_methodt::convert_invoke(
22582266
// We set opaque methods as final to avoid assuming they can be overridden.
22592267
if(
22602268
method_symbol == symbol_table.symbols.end() &&
2261-
!(is_virtual &&
2262-
is_method_inherited(arg0.get(ID_C_class), arg0.get(ID_component_name))))
2269+
!(is_virtual && is_method_inherited(
2270+
class_method_descriptor.get_class_name(),
2271+
class_method_descriptor.get_component_name())))
22632272
{
22642273
create_method_stub_symbol(
22652274
invoked_method_id,
2266-
arg0.get(ID_C_base_name),
2267-
id2string(arg0.get(ID_C_class)).substr(6) + "." +
2268-
id2string(arg0.get(ID_C_base_name)) + "()",
2275+
class_method_descriptor.get_base_name(),
2276+
id2string(class_method_descriptor.get_class_name()).substr(6) + "." +
2277+
id2string(class_method_descriptor.get_base_name()) + "()",
22692278
method_type,
2270-
arg0.get(ID_C_class),
2279+
class_method_descriptor.get_class_name(),
22712280
symbol_table,
22722281
get_message_handler());
22732282
}
@@ -2278,7 +2287,7 @@ void java_bytecode_convert_methodt::convert_invoke(
22782287
// dynamic binding
22792288
PRECONDITION(use_this);
22802289
PRECONDITION(!arguments.empty());
2281-
function = arg0;
2290+
function = class_method_descriptor;
22822291
// Populate needed methods later,
22832292
// once we know what object types can exist.
22842293
}
@@ -2290,7 +2299,8 @@ void java_bytecode_convert_methodt::convert_invoke(
22902299
{
22912300
needed_lazy_methods->add_needed_method(invoked_method_id);
22922301
// Calling a static method causes static initialization:
2293-
needed_lazy_methods->add_needed_class(arg0.get(ID_C_class));
2302+
needed_lazy_methods->add_needed_class(
2303+
class_method_descriptor.get_class_name());
22942304
}
22952305
}
22962306

@@ -2305,7 +2315,8 @@ void java_bytecode_convert_methodt::convert_invoke(
23052315

23062316
if(!use_this)
23072317
{
2308-
codet clinit_call = get_clinit_call(arg0.get(ID_C_class));
2318+
codet clinit_call =
2319+
get_clinit_call(class_method_descriptor.get_class_name());
23092320
if(clinit_call.get_statement() != ID_skip)
23102321
c = code_blockt({clinit_call, c});
23112322
}

jbmc/src/java_bytecode/java_bytecode_convert_method_class.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ class java_bytecode_convert_methodt:public messaget
494494
void convert_invoke(
495495
source_locationt location,
496496
const irep_idt &statement,
497-
exprt &arg0,
497+
class_method_descriptor_exprt &class_method_descriptor,
498498
codet &c,
499499
exprt::operandst &results);
500500

jbmc/src/java_bytecode/java_bytecode_parser.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -763,13 +763,8 @@ void java_bytecode_parsert::rconstant_pool()
763763
irep_idt identifier=
764764
id2string(class_name)+"."+id2string(component_name);
765765

766-
exprt virtual_function(ID_virtual_function, type);
767-
virtual_function.set(ID_component_name, component_name);
768-
virtual_function.set(ID_C_class, class_name);
769-
virtual_function.set(ID_C_base_name, name_entry.s);
770-
virtual_function.set(ID_identifier, identifier);
771-
772-
entry.expr = virtual_function;
766+
entry.expr = class_method_descriptor_exprt{
767+
type, component_name, class_name, name_entry.s, identifier};
773768
}
774769
break;
775770

jbmc/unit/java_bytecode/goto-programs/remove_virtual_functions_without_fallback.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,11 @@ SCENARIO(
133133
const symbolt &callee_symbol =
134134
symbol_table.lookup_ref("java::VirtualFunctionsTestParent.f:()V");
135135

136-
exprt callee(ID_virtual_function, callee_symbol.type);
137-
callee.set(ID_identifier, callee_symbol.name);
138-
callee.set(ID_C_class, "java::VirtualFunctionsTestParent");
139-
callee.set(ID_component_name, "f:()V");
136+
class_method_descriptor_exprt callee{callee_symbol.type,
137+
"f:()V",
138+
"java::VirtualFunctionsTestParent",
139+
"f",
140+
callee_symbol.name};
140141

141142
const code_function_callt call(
142143
callee,

jbmc/unit/java_bytecode/java_bytecode_instrument/virtual_call_null_checks.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static bool is_expected_virtualmethod_call(
2424
return false;
2525
const auto &virtual_call = to_code_function_call(instruction.code);
2626
const auto &called_function = virtual_call.function();
27-
if(called_function.id() != ID_virtual_function)
27+
if(!can_cast_expr<class_method_descriptor_exprt>(called_function))
2828
return false;
2929
if(called_function.get(ID_identifier) != "java::B.virtualmethod:()V")
3030
return false;

0 commit comments

Comments
 (0)