1/*******************************************************************\
3Module: Java lambda code synthesis
7\*******************************************************************/
31 if(
c ==
'$' ||
c ==
':' ||
c ==
'.')
41 return "java::lambda_synthetic_class$" +
54static std::optional<java_class_typet::java_lambda_method_handlet>
60 // Check if we don't have enough bootstrap methods to satisfy the requested
61 // lambda. This could happen if we fail to parse one of the methods, or if
62 // the class type is partly or entirely synthetic, such as the types created
63 // internally by the string solver.
64 if(index >= lambda_method_handles.size())
67 // If the lambda method handle has an unknown type, it does not refer to
68 // any symbol (it has an empty identifier)
76static std::optional<java_class_typet::java_lambda_method_handlet>
88 const auto &lambda_method_handles =
class_type.lambda_method_handles();
111 return a->get_base_name() ==
b->get_base_name()
112 ? (
a->get_descriptor() ==
b->get_descriptor()
114 :
a->get_descriptor() <
b->get_descriptor())
115 :
a->get_base_name() <
b->get_base_name();
137 static const irep_idt jlo =
"java::java.lang.Object";
138 // Terminate recursion at Object; any other base of an interface must
139 // itself be an interface.
154 // First accumulate definitions from child types:
155 for(
const auto &base :
interface.bases())
163 // Any base definition fills any abstract definition from another base:
168 // An abstract method incoming from a base falls to any existing
169 // definition, so only insert if not present:
175 // Now insert defintions from this class:
176 for(
const auto &method :
interface.methods())
178 static const irep_idt equals =
"equals";
183 (method.get_base_name() == equals &&
185 (method.get_base_name() ==
hashCode &&
188 // Ignore any uses of functions that are certainly defined on
189 // java.lang.Object-- even if explicitly made abstract, they can't be the
190 // implemented method of a functional interface.
194 // Note unlike inherited definitions, an abstract definition here *does*
195 // wipe out a non-abstract definition (i.e. a default method) from a parent
227 "produces a type with at least two unimplemented methods");
236 "produces a type with no unimplemented methods");
257 // Tag = name without 'java::' prefix, matching the convention used by
258 // java_bytecode_convert_class.cpp
268 // Add the class fields:
319 param.set_identifier(
363 param.set_identifier(
373// invokedynamic will be called with operands that should be stored in a
374// synthetic object implementing the interface type that it returns. For
375// example, "invokedynamic f(a, b, c) -> MyInterface" should result in the
376// creation of the synthetic class:
377// public class SyntheticCapture implements MyInterface {
381// public SyntheticCapture(int a, float b, Other c) {
382// this.a = a; this.b = b; this.c = c;
384// public void myInterfaceMethod(int d) {
388// This method just creates the outline; the methods will be populated on
389// demand via java_bytecode_languaget::convert_lazy_method.
391// Check that we understand the lambda method handle; if we don't then
392// we will not create a synthetic class at all, and the corresponding
393// invoke instruction will return null when eventually converted by
394// java_bytecode_convert_method.
404 for(
const auto &instruction : instructions)
415 <<
" address " << instruction.address
430 <<
" address " << instruction.address <<
" for lambda: "
447#if defined(__GNUC__) && __GNUC__ >= 14
490 parameters.at(0).get_identifier(), parameters.at(0).type());
493 // Call super-constructor (always java.lang.Object):
515 // Store captured parameters:
519 // Give the parameter its symbol:
538 return std::move(result);
578 // We must instantiate the object, then call the requested constructor
582 "REF_NewInvokeSpecial lambda must refer to a constructor");
588 // Call static init if it exists:
595 // Make a local to hold the new instance:
598 "newinvokespecial_instance",
603 // Instantiate the object:
612static std::optional<irep_idt>
620 : std::optional<irep_idt>{};
641 // Neither final nor static; make a class_method_descriptor_exprt that will
642 // trigger remove_virtual_functions to produce a virtual dispatch table:
646 const irep_idt mangled_method_name =
690 const std::string &
role)
701 // One is a pointer, the other a primitive -- box or unbox as necessary, and
702 // check the types are consistent:
708 "A Java non-pointer type involved in a type disagreement should"
749 const std::string &
role)
778 // Call the bound method with the capture parameters, then the actual
779 // parameters. Note one of the capture params might be the `this` parameter
780 // of a virtual call -- that depends on whether the callee is a static or an
788 const auto ¶meters = function_type.parameters();
794 parameters.at(0).get_identifier(), parameters.at(0).type());
800 if(
field.get_name() ==
"@java.lang.Object")
808 // Give the parameter its symbol:
841 // Prepend the newly created object to the lambda arg list:
853 // Adjust boxing if required:
859 "should have args for every parameter");
868 "param" + std::to_string(i));
878 function_type.return_type(),
892 // Return the newly-created object.
897 return std::move(result);
struct bytecode_infot const bytecode_info[]
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Internally generated symbol table entryThis is a symbol generated as part of translation to or modifi...
An expression describing a method on a class.
A codet representing sequential composition of program statements.
void add(const codet &code)
A goto_instruction_codet representing the declaration of a local variable.
A codet representing an assignment in the program.
goto_instruction_codet representation of a function call statement.
exprt::operandst argumentst
goto_instruction_codet representation of a "return from a function" statement.
std::vector< parametert > parameterst
void set_is_constructor()
const parameterst & parameters() const
const typet & return_type() const
Data structure for representing an arbitrary statement in a program.
Operator to dereference a pointer.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Base class for all expressions.
typet & type()
Return the type of the expression.
Represents a lambda call to a method.
std::vector< java_lambda_method_handlet > java_lambda_method_handlest
@ LAMBDA_VIRTUAL_METHOD_HANDLE
Virtual call to the given interface or method.
@ UNKNOWN_HANDLE
Can't be called.
@ LAMBDA_CONSTRUCTOR_HANDLE
Instantiate the needed type then call a constructor.
Extract member of struct or union.
Class that provides messages with a built-in verbosity 'level'.
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
const std::string message
no_unique_unimplemented_method_exceptiont(const std::string &s)
Symbol table entry of function parameterThis is a symbol generated as part of type checking.
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
An expression containing a side effect.
A struct tag type, i.e., struct_typet with an identifier.
Expression to hold a symbol (variable)
The symbol table base class interface.
const symbolt * lookup(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
bool add(const symbolt &symbol)
Add a new symbol to the symbol table.
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
Symbol table entry describing a data typeThis is a symbol generated as part of type checking.
static exprt conditional_cast(const exprt &expr, const typet &type)
The type of an expression, extends irept.
const std::string & id2string(const irep_idt &d)
void create_method_stub_symbol(const irep_idt &identifier, const irep_idt &base_name, const irep_idt &pretty_name, const typet &type, const irep_idt &declaring_class, symbol_table_baset &symbol_table, message_handlert &message_handler)
JAVA Bytecode Language Conversion.
irep_idt clinit_wrapper_name(const irep_idt &class_name)
Get the Java static initializer wrapper name for a given class (the wrapper checks if static initiali...
reference_typet java_reference_type(const typet &subtype)
const java_method_typet & to_java_method_type(const typet &type)
const java_reference_typet & to_java_reference_type(const typet &type)
const java_class_typet & to_java_class_type(const typet &type)
const java_primitive_type_infot * get_java_primitive_type_info(const typet &maybe_primitive_type)
If primitive_type is a Java primitive type, return information about it, otherwise return null.
const java_boxed_type_infot * get_boxed_type_info_by_name(const irep_idt &type_name)
If type_name is a Java boxed type tag, return information about it, otherwise return null.
std::optional< irep_idt > declaring_class(const symbolt &symbol)
Gets the identifier of the class which declared a given symbol.
void set_declaring_class(symbolt &symbol, const irep_idt &declaring_class)
Sets the identifier of the class which declared a given symbol to declaring_class.
irep_idt strip_java_namespace_prefix(const irep_idt &to_strip)
Strip java:: prefix from given identifier.
static symbolt implemented_method_symbol(synthetic_methods_mapt &synthetic_methods, const java_class_typet::methodt &method_to_implement, const irep_idt &synthetic_class_name)
symbolt synthetic_class_symbol(const irep_idt &synthetic_class_name, const java_class_typet::java_lambda_method_handlet &lambda_method_handle, const struct_tag_typet &functional_interface_tag, const java_method_typet &dynamic_method_type)
exprt make_function_expr(const symbolt &function_symbol, const symbol_table_baset &symbol_table)
Produce a class_method_descriptor_exprt or symbol_exprt for function_symbol depending on whether virt...
void create_invokedynamic_synthetic_classes(const irep_idt &method_identifier, const java_bytecode_parse_treet::methodt::instructionst &instructions, symbol_table_baset &symbol_table, synthetic_methods_mapt &synthetic_methods, message_handlert &message_handler)
static std::optional< java_class_typet::java_lambda_method_handlet > lambda_method_handle(const symbol_table_baset &symbol_table, const irep_idt &method_identifier, const java_method_typet &dynamic_method_type)
exprt box_or_unbox_type_if_necessary(exprt expr, const typet &required_type, code_blockt &code_block, symbol_table_baset &symbol_table, const irep_idt &function_id, const std::string &role)
If expr needs (un)boxing to satisfy required_type, add the required symbols to symbol_table and code ...
std::map< const java_class_typet::methodt *, bool, compare_base_name_and_descriptort > methods_by_name_and_descriptort
Map from method, indexed by name and descriptor but not defining class, onto defined-ness (i....
codet invokedynamic_synthetic_constructor(const irep_idt &function_id, symbol_table_baset &symbol_table, message_handlert &message_handler)
Create invokedynamic synthetic constructor.
static symbol_exprt instantiate_new_object(const irep_idt &function_id, const symbolt &lambda_method_symbol, symbol_table_baset &symbol_table, code_blockt &result)
Instantiates an object suitable for calling a given constructor (but does not actually call it).
static const java_class_typet::methodt * try_get_unique_unimplemented_method(const symbol_table_baset &symbol_table, const struct_tag_typet &functional_interface_tag, const irep_idt &method_identifier, const int instruction_address, const messaget &log)
static std::optional< irep_idt > get_unboxing_method(const pointer_typet &maybe_boxed_type)
If maybe_boxed_type is a boxed primitive return its unboxing method; otherwise return empty.
static symbol_exprt create_and_declare_local(const irep_idt &function_id, const irep_idt &basename, const typet &type, symbol_table_baset &symbol_table, code_blockt &method)
static std::string escape_symbol_special_chars(std::string input)
static const symbolt & get_or_create_method_symbol(const irep_idt &identifier, const irep_idt &base_name, const irep_idt &pretty_name, const typet &type, const irep_idt &declaring_class, symbol_table_baset &symbol_table, message_handlert &log)
exprt adjust_type_if_necessary(exprt expr, const typet &required_type, code_blockt &code_block, symbol_table_baset &symbol_table, const irep_idt &function_id, const std::string &role)
Box or unbox expr as per box_or_unbox_type_if_necessary, then cast the result to required_type.
codet invokedynamic_synthetic_method(const irep_idt &function_id, symbol_table_baset &symbol_table, message_handlert &message_handler)
Create the body for the synthetic method implementing an invokedynamic method.
static std::optional< java_class_typet::java_lambda_method_handlet > get_lambda_method_handle(const symbol_table_baset &symbol_table, const java_class_typet::java_lambda_method_handlest &lambda_method_handles, const size_t index)
Retrieves the symbol of the lambda method associated with the given lambda method handle (bootstrap m...
irep_idt lambda_synthetic_class_name(const irep_idt &method_identifier, std::size_t instruction_address)
static symbolt constructor_symbol(synthetic_methods_mapt &synthetic_methods, const irep_idt &synthetic_class_name, java_method_typet constructor_type)
static const methods_by_name_and_descriptort get_interface_methods(const irep_idt &interface_id, const namespacet &ns)
Find all methods defined by this method and its parent types, returned as a map from const java_class...
Java lambda code synthesis.
bool can_cast_type< pointer_typet >(const typet &type)
Check whether a reference to a typet is a pointer_typet.
const reference_typet & to_reference_type(const typet &type)
Cast a typet to a reference_typet.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
#define POSTCONDITION(CONDITION)
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
const class_typet & to_class_type(const typet &type)
Cast a typet to a class_typet.
int strcmp(const char *s1, const char *s2)
int operator()(const java_class_typet::methodt *a, const java_class_typet::methodt *b) const
Return type for get_boxed_type_info_by_name.
std::vector< instructiont > instructionst
Synthetic methods are particular methods internally generated by the Java frontend,...
std::unordered_map< irep_idt, synthetic_method_typet > synthetic_methods_mapt
Maps method names on to a synthetic method kind.
@ INVOKEDYNAMIC_METHOD
A generated method for a class capturing the parameters of an invokedynamic instruction.
@ INVOKEDYNAMIC_CAPTURE_CONSTRUCTOR
A generated constructor for a class capturing the parameters of an invokedynamic instruction.