|
21 | 21 | #include "java_string_literal_expr.h"
|
22 | 22 | #include "java_types.h"
|
23 | 23 | #include "java_utils.h"
|
| 24 | +#include "lambda_synthesis.h" |
24 | 25 | #include "pattern.h"
|
25 | 26 | #include "remove_exceptions.h"
|
26 | 27 |
|
@@ -303,24 +304,6 @@ java_method_typet member_type_lazy(
|
303 | 304 | return to_java_method_type(*member_type_from_descriptor);
|
304 | 305 | }
|
305 | 306 |
|
306 |
| -/// Retrieves the symbol of the lambda method associated with the given |
307 |
| -/// lambda method handle (bootstrap method). |
308 |
| -/// \param lambda_method_handles: Vector of lambda method handles (bootstrap |
309 |
| -/// methods) of the class where the lambda is called |
310 |
| -/// \param index: Index of the lambda method handle in the vector |
311 |
| -/// \return Symbol of the lambda method if the method handle has a known type |
312 |
| -optionalt<symbolt> java_bytecode_convert_methodt::get_lambda_method_symbol( |
313 |
| - const java_class_typet::java_lambda_method_handlest &lambda_method_handles, |
314 |
| - const size_t index) |
315 |
| -{ |
316 |
| - const irept &lambda_method_handle = lambda_method_handles.at(index); |
317 |
| - // If the lambda method handle has an unknown type, it does not refer to |
318 |
| - // any symbol (it has an empty identifier) |
319 |
| - if(!lambda_method_handle.id().empty()) |
320 |
| - return symbol_table.lookup_ref(lambda_method_handle.id()); |
321 |
| - return {}; |
322 |
| -} |
323 |
| - |
324 | 307 | /// This creates a method symbol in the symtab, but doesn't actually perform
|
325 | 308 | /// method conversion just yet. The caller should call
|
326 | 309 | /// java_bytecode_convert_method later to give the symbol/method a body.
|
@@ -631,8 +614,7 @@ void java_bytecode_convert_methodt::convert(
|
631 | 614 | if((!m.is_abstract) && (!m.is_native))
|
632 | 615 | {
|
633 | 616 | code_blockt code(convert_parameter_annotations(m, method_type));
|
634 |
| - code.append(convert_instructions( |
635 |
| - m, to_java_class_type(class_symbol.type).lambda_method_handles())); |
| 617 | + code.append(convert_instructions(m)); |
636 | 618 | method_symbol.value = std::move(code);
|
637 | 619 | }
|
638 | 620 | }
|
@@ -1061,9 +1043,8 @@ code_blockt java_bytecode_convert_methodt::convert_parameter_annotations(
|
1061 | 1043 | return code;
|
1062 | 1044 | }
|
1063 | 1045 |
|
1064 |
| -code_blockt java_bytecode_convert_methodt::convert_instructions( |
1065 |
| - const methodt &method, |
1066 |
| - const java_class_typet::java_lambda_method_handlest &lambda_method_handles) |
| 1046 | +code_blockt |
| 1047 | +java_bytecode_convert_methodt::convert_instructions(const methodt &method) |
1067 | 1048 | {
|
1068 | 1049 | const instructionst &instructions=method.instructions;
|
1069 | 1050 |
|
@@ -1317,10 +1298,9 @@ code_blockt java_bytecode_convert_methodt::convert_instructions(
|
1317 | 1298 | }
|
1318 | 1299 | else if(bytecode == BC_invokedynamic)
|
1319 | 1300 | {
|
1320 |
| - // not used in Java |
1321 | 1301 | if(
|
1322 |
| - const auto res = convert_invoke_dynamic( |
1323 |
| - lambda_method_handles, i_it->source_location, arg0)) |
| 1302 | + const auto res = |
| 1303 | + convert_invoke_dynamic(i_it->source_location, i_it->address, arg0, c)) |
1324 | 1304 | {
|
1325 | 1305 | results.resize(1);
|
1326 | 1306 | results[0] = *res;
|
@@ -2957,40 +2937,71 @@ code_blockt java_bytecode_convert_methodt::convert_astore(
|
2957 | 2937 | }
|
2958 | 2938 |
|
2959 | 2939 | optionalt<exprt> java_bytecode_convert_methodt::convert_invoke_dynamic(
|
2960 |
| - const java_class_typet::java_lambda_method_handlest &lambda_method_handles, |
2961 | 2940 | const source_locationt &location,
|
2962 |
| - const exprt &arg0) |
| 2941 | + std::size_t instruction_address, |
| 2942 | + const exprt &arg0, |
| 2943 | + codet &result_code) |
2963 | 2944 | {
|
2964 | 2945 | const java_method_typet &method_type = to_java_method_type(arg0.type());
|
| 2946 | + const java_method_typet::parameterst ¶meters(method_type.parameters()); |
| 2947 | + const typet &return_type = method_type.return_type(); |
2965 | 2948 |
|
2966 |
| - const optionalt<symbolt> &lambda_method_symbol = get_lambda_method_symbol( |
2967 |
| - lambda_method_handles, |
2968 |
| - method_type.get_int(ID_java_lambda_method_handle_index)); |
2969 |
| - if(lambda_method_symbol.has_value()) |
2970 |
| - debug() << "Converting invokedynamic for lambda: " |
2971 |
| - << lambda_method_symbol.value().name << eom; |
2972 |
| - else |
2973 |
| - debug() << "Converting invokedynamic for lambda with unknown handle " |
2974 |
| - "type" |
2975 |
| - << eom; |
| 2949 | + // Note these must be popped regardless of whether we understand the lambda |
| 2950 | + // method or not |
| 2951 | + code_function_callt::argumentst arguments = pop(parameters.size()); |
2976 | 2952 |
|
2977 |
| - const java_method_typet::parameterst ¶meters(method_type.parameters()); |
| 2953 | + irep_idt synthetic_class_name = |
| 2954 | + lambda_synthetic_class_name(method_id, instruction_address); |
2978 | 2955 |
|
2979 |
| - pop(parameters.size()); |
| 2956 | + if(!symbol_table.has_symbol(synthetic_class_name)) |
| 2957 | + { |
| 2958 | + // We failed to parse the invokedynamic handle as a Java 8+ lambda; |
| 2959 | + // give up and return null. |
| 2960 | + const auto value = zero_initializer(return_type, location, ns); |
| 2961 | + if(!value.has_value()) |
| 2962 | + { |
| 2963 | + error().source_location = location; |
| 2964 | + error() << "failed to zero-initialize return type" << eom; |
| 2965 | + throw 0; |
| 2966 | + } |
| 2967 | + return value; |
| 2968 | + } |
2980 | 2969 |
|
2981 |
| - const typet &return_type = method_type.return_type(); |
| 2970 | + // Construct an instance of the synthetic class created for this invokedynamic |
| 2971 | + // site: |
2982 | 2972 |
|
2983 |
| - if(return_type.id() == ID_empty) |
2984 |
| - return {}; |
| 2973 | + irep_idt constructor_name = id2string(synthetic_class_name) + ".<init>"; |
| 2974 | + |
| 2975 | + const symbolt &constructor_symbol = ns.lookup(constructor_name); |
2985 | 2976 |
|
2986 |
| - const auto value = zero_initializer(return_type, location, ns); |
2987 |
| - if(!value.has_value()) |
| 2977 | + code_blockt result; |
| 2978 | + |
| 2979 | + // SyntheticType lambda_new = new SyntheticType; |
| 2980 | + const reference_typet ref_type = |
| 2981 | + java_reference_type(struct_tag_typet(synthetic_class_name)); |
| 2982 | + side_effect_exprt java_new_expr(ID_java_new, ref_type, location); |
| 2983 | + const exprt new_instance = tmp_variable("lambda_new", ref_type); |
| 2984 | + result.add(code_assignt(new_instance, java_new_expr, location)); |
| 2985 | + |
| 2986 | + // lambda_new.<init>(capture_1, capture_2, ...); |
| 2987 | + // Add the implicit 'this' parameter: |
| 2988 | + arguments.insert(arguments.begin(), new_instance); |
| 2989 | + code_function_callt constructor_call( |
| 2990 | + constructor_symbol.symbol_expr(), arguments); |
| 2991 | + constructor_call.add_source_location() = location; |
| 2992 | + result.add(constructor_call); |
| 2993 | + if(needed_lazy_methods) |
2988 | 2994 | {
|
2989 |
| - error().source_location = location; |
2990 |
| - error() << "failed to zero-initialize return type" << eom; |
2991 |
| - throw 0; |
| 2995 | + needed_lazy_methods->add_needed_method(constructor_symbol.name); |
| 2996 | + needed_lazy_methods->add_needed_class(synthetic_class_name); |
2992 | 2997 | }
|
2993 |
| - return value; |
| 2998 | + |
| 2999 | + result_code = std::move(result); |
| 3000 | + |
| 3001 | + if(return_type.id() == ID_empty) |
| 3002 | + return {}; |
| 3003 | + else |
| 3004 | + return new_instance; |
2994 | 3005 | }
|
2995 | 3006 |
|
2996 | 3007 | void java_bytecode_convert_methodt::draw_edges_from_ret_to_jsr(
|
|
0 commit comments