Skip to content

Commit 5e95689

Browse files
Merge pull request #5145 from thomasspriggs/tas/virtual-function-expr
Refinements to `class_method_descriptor_exprt`
2 parents 5d6d1ae + 89d2d73 commit 5e95689

File tree

7 files changed

+96
-62
lines changed

7 files changed

+96
-62
lines changed

jbmc/src/java_bytecode/ci_lazy_methods.cpp

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ bool ci_lazy_methodst::handle_virtual_methods_with_no_callees(
263263
// didn't already exist. It can't be instantiated already, otherwise it
264264
// would give a concrete definition of the called method, and
265265
// candidate_target_methods would be non-empty.
266-
const irep_idt &call_class = virtual_function.get_class_name();
266+
const irep_idt &call_class = virtual_function.class_id();
267267
bool was_missing = instantiated_classes.count(call_class) == 0;
268268
CHECK_RETURN(was_missing);
269269
any_new_classes = true;
@@ -292,13 +292,13 @@ bool ci_lazy_methodst::handle_virtual_methods_with_no_callees(
292292
}
293293

294294
// Check that `get_virtual_method_target` returns a method now
295-
const irep_idt &call_basename = virtual_function.get_component_name();
296-
const irep_idt method_name = get_virtual_method_target(
297-
instantiated_classes, call_basename, call_class, symbol_table);
298-
CHECK_RETURN(!method_name.empty());
295+
const irep_idt &method_name = virtual_function.mangled_method_name();
296+
const irep_idt method_id = get_virtual_method_target(
297+
instantiated_classes, method_name, call_class, symbol_table);
298+
CHECK_RETURN(!method_id.empty());
299299

300300
// Add what it returns to methods_to_convert_later
301-
methods_to_convert_later.insert(method_name);
301+
methods_to_convert_later.insert(method_id);
302302
}
303303
return any_new_classes;
304304
}
@@ -477,24 +477,19 @@ void ci_lazy_methodst::get_virtual_method_targets(
477477
std::unordered_set<irep_idt> &callable_methods,
478478
symbol_tablet &symbol_table)
479479
{
480-
const auto &call_class = called_function.get_class_name();
481-
INVARIANT(
482-
!call_class.empty(), "All virtual calls should be aimed at a class");
483-
const auto &call_basename = called_function.get_component_name();
484-
INVARIANT(
485-
!call_basename.empty(),
486-
"Virtual function must have a reasonable name after removing class");
480+
const auto &call_class = called_function.class_id();
481+
const auto &method_name = called_function.mangled_method_name();
487482

488483
class_hierarchyt::idst self_and_child_classes =
489484
class_hierarchy.get_children_trans(call_class);
490485
self_and_child_classes.push_back(call_class);
491486

492487
for(const irep_idt &class_name : self_and_child_classes)
493488
{
494-
const irep_idt method_name = get_virtual_method_target(
495-
instantiated_classes, call_basename, class_name, symbol_table);
496-
if(!method_name.empty())
497-
callable_methods.insert(method_name);
489+
const irep_idt method_id = get_virtual_method_target(
490+
instantiated_classes, method_name, class_name, symbol_table);
491+
if(!method_id.empty())
492+
callable_methods.insert(method_id);
498493
}
499494
}
500495

jbmc/src/java_bytecode/expr2java.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,9 +422,8 @@ std::string expr2javat::convert_with_precedence(
422422
{
423423
const class_method_descriptor_exprt &virtual_function =
424424
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()) + ")";
425+
return "CLASS_METHOD_DESCRIPTOR(" + id2string(virtual_function.class_id()) +
426+
"." + id2string(virtual_function.mangled_method_name()) + ")";
428427
}
429428
else if(
430429
const auto &literal = expr_try_dynamic_cast<java_string_literal_exprt>(src))

jbmc/src/java_bytecode/java_bytecode_convert_method.cpp

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,11 +2231,11 @@ void java_bytecode_convert_methodt::convert_invoke(
22312231

22322232
if(use_this)
22332233
{
2234-
irep_idt classname = class_method_descriptor.get(ID_C_class);
2234+
const irep_idt class_id = class_method_descriptor.class_id();
22352235

22362236
if(parameters.empty() || !parameters[0].get_this())
22372237
{
2238-
typet thistype = struct_tag_typet(classname);
2238+
typet thistype = struct_tag_typet(class_id);
22392239
reference_typet object_ref_type = java_reference_type(thistype);
22402240
java_method_typet::parametert this_p(object_ref_type);
22412241
this_p.set_this();
@@ -2250,7 +2250,7 @@ void java_bytecode_convert_methodt::convert_invoke(
22502250
if(is_constructor(invoked_method_id))
22512251
{
22522252
if(needed_lazy_methods)
2253-
needed_lazy_methods->add_needed_class(classname);
2253+
needed_lazy_methods->add_needed_class(class_id);
22542254
method_type.set_is_constructor();
22552255
}
22562256
else
@@ -2297,16 +2297,16 @@ void java_bytecode_convert_methodt::convert_invoke(
22972297
if(
22982298
method_symbol == symbol_table.symbols.end() &&
22992299
!(is_virtual && is_method_inherited(
2300-
class_method_descriptor.get_class_name(),
2301-
class_method_descriptor.get_component_name())))
2300+
class_method_descriptor.class_id(),
2301+
class_method_descriptor.mangled_method_name())))
23022302
{
23032303
create_method_stub_symbol(
23042304
invoked_method_id,
2305-
class_method_descriptor.get_base_name(),
2306-
id2string(class_method_descriptor.get_class_name()).substr(6) + "." +
2307-
id2string(class_method_descriptor.get_base_name()) + "()",
2305+
class_method_descriptor.base_method_name(),
2306+
id2string(class_method_descriptor.class_id()).substr(6) + "." +
2307+
id2string(class_method_descriptor.base_method_name()) + "()",
23082308
method_type,
2309-
class_method_descriptor.get_class_name(),
2309+
class_method_descriptor.class_id(),
23102310
symbol_table,
23112311
get_message_handler());
23122312
}
@@ -2329,8 +2329,7 @@ void java_bytecode_convert_methodt::convert_invoke(
23292329
{
23302330
needed_lazy_methods->add_needed_method(invoked_method_id);
23312331
// Calling a static method causes static initialization:
2332-
needed_lazy_methods->add_needed_class(
2333-
class_method_descriptor.get_class_name());
2332+
needed_lazy_methods->add_needed_class(class_method_descriptor.class_id());
23342333
}
23352334
}
23362335

@@ -2345,8 +2344,7 @@ void java_bytecode_convert_methodt::convert_invoke(
23452344

23462345
if(!use_this)
23472346
{
2348-
codet clinit_call =
2349-
get_clinit_call(class_method_descriptor.get_class_name());
2347+
codet clinit_call = get_clinit_call(class_method_descriptor.class_id());
23502348
if(clinit_call.get_statement() != ID_skip)
23512349
c = code_blockt({clinit_call, c});
23522350
}
@@ -3257,13 +3255,13 @@ void java_bytecode_convert_method(
32573255
/// a method inherited from a class (and not an interface!) from which
32583256
/// \p classname inherits, either directly or indirectly.
32593257
/// \param classname: class whose method is referenced
3260-
/// \param methodid: method basename
3258+
/// \param mangled_method_name: The particular overload of a given method.
32613259
bool java_bytecode_convert_methodt::is_method_inherited(
32623260
const irep_idt &classname,
3263-
const irep_idt &methodid) const
3261+
const irep_idt &mangled_method_name) const
32643262
{
3265-
const auto inherited_method =
3266-
get_inherited_component(classname, methodid, symbol_table, false);
3263+
const auto inherited_method = get_inherited_component(
3264+
classname, mangled_method_name, symbol_table, false);
32673265
return inherited_method.has_value();
32683266
}
32693267

jbmc/src/java_bytecode/java_bytecode_convert_method_class.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ class java_bytecode_convert_methodt:public messaget
311311

312312
bool is_method_inherited(
313313
const irep_idt &classname,
314-
const irep_idt &methodid) const;
314+
const irep_idt &mangled_method_name) const;
315315

316316
irep_idt get_static_field(
317317
const irep_idt &class_identifier, const irep_idt &component_name) const;

jbmc/src/java_bytecode/java_bytecode_parser.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -754,17 +754,14 @@ void java_bytecode_parsert::rconstant_pool()
754754

755755
auto class_tag = java_classname(id2string(class_name_entry.s));
756756

757-
irep_idt component_name=
758-
id2string(name_entry.s)+
759-
":"+id2string(pool_entry(nameandtype_entry.ref2).s);
757+
irep_idt mangled_method_name =
758+
id2string(name_entry.s) + ":" +
759+
id2string(pool_entry(nameandtype_entry.ref2).s);
760760

761-
irep_idt class_name = class_tag.get_identifier();
762-
763-
irep_idt identifier=
764-
id2string(class_name)+"."+id2string(component_name);
761+
irep_idt class_id = class_tag.get_identifier();
765762

766763
entry.expr = class_method_descriptor_exprt{
767-
type, component_name, class_name, name_entry.s, identifier};
764+
type, mangled_method_name, class_id, name_entry.s};
768765
}
769766
break;
770767

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

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

136-
class_method_descriptor_exprt callee{callee_symbol.type,
137-
"f:()V",
138-
"java::VirtualFunctionsTestParent",
139-
"f",
140-
callee_symbol.name};
136+
class_method_descriptor_exprt callee{
137+
callee_symbol.type, "f:()V", "java::VirtualFunctionsTestParent", "f"};
141138

142139
const code_function_callt call(
143140
callee,

src/util/std_expr.h

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4696,45 +4696,93 @@ inline array_comprehension_exprt &to_array_comprehension_expr(exprt &expr)
46964696
return ret;
46974697
}
46984698

4699+
inline void validate_expr(const class class_method_descriptor_exprt &value);
4700+
46994701
/// An expression describing a method on a class
47004702
class class_method_descriptor_exprt : public nullary_exprt
47014703
{
47024704
public:
4705+
/// \param _type: The type of the method which this expression refers to.
4706+
/// \param class_id: Unique identifier in the symbol table, of the compile
4707+
/// time type of the class which this expression is applied to. For example
4708+
/// this could be - `java::java.lang.Object`.
4709+
/// \param base_method_name: The name of the method to which this expression
4710+
/// is applied as would be seen in the source code. For example this could
4711+
/// be - `toString`.
4712+
/// \param mangled_method_name: The method name after mangling it by
4713+
/// combining it with the descriptor. The mangled name is distinguished from
4714+
/// other overloads of the method with different counts of or types of
4715+
/// parameters. It is not distinguished between different implementations
4716+
/// within a class hierarchy. For example if the overall expression refers
4717+
/// to the `java.lang.Object.toString` method, then the mangled_method_name
4718+
/// would be `toString:()Ljava/lang/String;`
47034719
explicit class_method_descriptor_exprt(
47044720
typet _type,
4705-
irep_idt component_name,
4706-
irep_idt class_name,
4707-
irep_idt base_name,
4708-
irep_idt identifier)
4721+
irep_idt mangled_method_name,
4722+
irep_idt class_id,
4723+
irep_idt base_method_name)
47094724
: nullary_exprt(ID_virtual_function, std::move(_type))
47104725
{
4711-
set(ID_component_name, std::move(component_name));
4712-
set(ID_C_class, std::move(class_name));
4713-
set(ID_C_base_name, std::move(base_name));
4714-
set(ID_identifier, std::move(identifier));
4726+
irep_idt id = id2string(class_id) + "." + id2string(mangled_method_name);
4727+
set(ID_component_name, std::move(mangled_method_name));
4728+
set(ID_C_class, std::move(class_id));
4729+
set(ID_C_base_name, std::move(base_method_name));
4730+
set(ID_identifier, std::move(id));
4731+
validate_expr(*this);
47154732
}
47164733

4717-
const irep_idt &get_component_name() const
4734+
/// The method name after mangling it by combining it with the descriptor.
4735+
/// The mangled name is distinguished from other overloads of the method with
4736+
/// different counts of or types of parameters. It is not distinguished
4737+
/// between different implementations within a class hierarchy. For example if
4738+
/// the overall expression refers to the `java.lang.Object.toString` method,
4739+
/// then the mangled_method_name would be `toString:()Ljava/lang/String;`
4740+
const irep_idt &mangled_method_name() const
47184741
{
47194742
return get(ID_component_name);
47204743
}
47214744

4722-
const irep_idt &get_class_name() const
4745+
/// Unique identifier in the symbol table, of the compile time type of the
4746+
/// class which this expression is applied to. For example this could be -
4747+
/// `java::java.lang.Object`.
4748+
const irep_idt &class_id() const
47234749
{
47244750
return get(ID_C_class);
47254751
}
47264752

4727-
const irep_idt &get_base_name() const
4753+
/// The name of the method to which this expression is applied as would be
4754+
/// seen in the source code. For example this could be - `toString`.
4755+
const irep_idt &base_method_name() const
47284756
{
47294757
return get(ID_C_base_name);
47304758
}
47314759

4760+
/// A unique identifier of the combination of class and method overload to
4761+
/// which this expression refers. For example this could be -
4762+
/// `java::java.lang.Object.toString:()Ljava/lang/String;`.
47324763
const irep_idt &get_identifier() const
47334764
{
47344765
return get(ID_identifier);
47354766
}
47364767
};
47374768

4769+
inline void validate_expr(const class class_method_descriptor_exprt &value)
4770+
{
4771+
validate_operands(value, 0, "class method descriptor must not have operands");
4772+
DATA_INVARIANT(
4773+
!value.mangled_method_name().empty(),
4774+
"class method descriptor must have a mangled method name.");
4775+
DATA_INVARIANT(
4776+
!value.class_id().empty(), "class method descriptor must have a class id.");
4777+
DATA_INVARIANT(
4778+
!value.base_method_name().empty(),
4779+
"class method descriptor must have a base method name.");
4780+
DATA_INVARIANT(
4781+
value.get_identifier() == id2string(value.class_id()) + "." +
4782+
id2string(value.mangled_method_name()),
4783+
"class method descriptor must have an identifier in the expected format.");
4784+
}
4785+
47384786
/// \brief Cast an exprt to a \ref class_method_descriptor_exprt
47394787
///
47404788
/// \a expr must be known to be \ref class_method_descriptor_exprt.

0 commit comments

Comments
 (0)