|
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.
|
@@ -629,9 +612,7 @@ void java_bytecode_convert_methodt::convert(
|
629 | 612 | current_method = method_symbol.name;
|
630 | 613 | method_has_this = method_type.has_this();
|
631 | 614 | if((!m.is_abstract) && (!m.is_native))
|
632 |
| - method_symbol.value = convert_instructions( |
633 |
| - m, |
634 |
| - to_java_class_type(class_symbol.type).lambda_method_handles()); |
| 615 | + method_symbol.value = convert_instructions(m); |
635 | 616 | }
|
636 | 617 |
|
637 | 618 | static irep_idt get_if_cmp_operator(const irep_idt &stmt)
|
@@ -1010,9 +991,8 @@ static std::size_t get_bytecode_type_width(const typet &ty)
|
1010 | 991 | return to_bitvector_type(ty).get_width();
|
1011 | 992 | }
|
1012 | 993 |
|
1013 |
| -code_blockt java_bytecode_convert_methodt::convert_instructions( |
1014 |
| - const methodt &method, |
1015 |
| - const java_class_typet::java_lambda_method_handlest &lambda_method_handles) |
| 994 | +code_blockt |
| 995 | +java_bytecode_convert_methodt::convert_instructions(const methodt &method) |
1016 | 996 | {
|
1017 | 997 | const instructionst &instructions=method.instructions;
|
1018 | 998 |
|
@@ -1264,10 +1244,9 @@ code_blockt java_bytecode_convert_methodt::convert_instructions(
|
1264 | 1244 | }
|
1265 | 1245 | else if(statement=="invokedynamic")
|
1266 | 1246 | {
|
1267 |
| - // not used in Java |
1268 | 1247 | if(
|
1269 |
| - const auto res = convert_invoke_dynamic( |
1270 |
| - lambda_method_handles, i_it->source_location, arg0)) |
| 1248 | + const auto res = |
| 1249 | + convert_invoke_dynamic(i_it->source_location, i_it->address, arg0, c)) |
1271 | 1250 | {
|
1272 | 1251 | results.resize(1);
|
1273 | 1252 | results[0] = *res;
|
@@ -2907,40 +2886,71 @@ code_blockt java_bytecode_convert_methodt::convert_astore(
|
2907 | 2886 | }
|
2908 | 2887 |
|
2909 | 2888 | optionalt<exprt> java_bytecode_convert_methodt::convert_invoke_dynamic(
|
2910 |
| - const java_class_typet::java_lambda_method_handlest &lambda_method_handles, |
2911 | 2889 | const source_locationt &location,
|
2912 |
| - const exprt &arg0) |
| 2890 | + std::size_t instruction_address, |
| 2891 | + const exprt &arg0, |
| 2892 | + codet &result_code) |
2913 | 2893 | {
|
2914 | 2894 | const java_method_typet &method_type = to_java_method_type(arg0.type());
|
| 2895 | + const java_method_typet::parameterst ¶meters(method_type.parameters()); |
| 2896 | + const typet &return_type = method_type.return_type(); |
2915 | 2897 |
|
2916 |
| - const optionalt<symbolt> &lambda_method_symbol = get_lambda_method_symbol( |
2917 |
| - lambda_method_handles, |
2918 |
| - method_type.get_int(ID_java_lambda_method_handle_index)); |
2919 |
| - if(lambda_method_symbol.has_value()) |
2920 |
| - debug() << "Converting invokedynamic for lambda: " |
2921 |
| - << lambda_method_symbol.value().name << eom; |
2922 |
| - else |
2923 |
| - debug() << "Converting invokedynamic for lambda with unknown handle " |
2924 |
| - "type" |
2925 |
| - << eom; |
| 2898 | + // Note these must be popped regardless of whether we understand the lambda |
| 2899 | + // method or not |
| 2900 | + code_function_callt::argumentst arguments = pop(parameters.size()); |
2926 | 2901 |
|
2927 |
| - const java_method_typet::parameterst ¶meters(method_type.parameters()); |
| 2902 | + irep_idt synthetic_class_name = |
| 2903 | + lambda_synthetic_class_name(method_id, instruction_address); |
| 2904 | + |
| 2905 | + if(!symbol_table.has_symbol(synthetic_class_name)) |
| 2906 | + { |
| 2907 | + // We failed to parse the invokedynamic handle as a Java 8+ lambda; |
| 2908 | + // give up and return null. |
| 2909 | + const auto value = zero_initializer(return_type, location, ns); |
| 2910 | + if(!value.has_value()) |
| 2911 | + { |
| 2912 | + error().source_location = location; |
| 2913 | + error() << "failed to zero-initialize return type" << eom; |
| 2914 | + throw 0; |
| 2915 | + } |
| 2916 | + return value; |
| 2917 | + } |
2928 | 2918 |
|
2929 |
| - pop(parameters.size()); |
| 2919 | + // Construct an instance of the synthetic class created for this invokedynamic |
| 2920 | + // site: |
2930 | 2921 |
|
2931 |
| - const typet &return_type = method_type.return_type(); |
| 2922 | + irep_idt constructor_name = id2string(synthetic_class_name) + ".<init>"; |
2932 | 2923 |
|
2933 |
| - if(return_type.id() == ID_empty) |
2934 |
| - return {}; |
| 2924 | + const symbolt &constructor_symbol = ns.lookup(constructor_name); |
2935 | 2925 |
|
2936 |
| - const auto value = zero_initializer(return_type, location, ns); |
2937 |
| - if(!value.has_value()) |
| 2926 | + code_blockt result; |
| 2927 | + |
| 2928 | + // SyntheticType lambda_new = new SyntheticType; |
| 2929 | + const reference_typet ref_type = |
| 2930 | + java_reference_type(struct_tag_typet(synthetic_class_name)); |
| 2931 | + side_effect_exprt java_new_expr(ID_java_new, ref_type, location); |
| 2932 | + const exprt new_instance = tmp_variable("lambda_new", ref_type); |
| 2933 | + result.add(code_assignt(new_instance, java_new_expr, location)); |
| 2934 | + |
| 2935 | + // lambda_new.<init>(capture_1, capture_2, ...); |
| 2936 | + // Add the implicit 'this' parameter: |
| 2937 | + arguments.insert(arguments.begin(), new_instance); |
| 2938 | + code_function_callt constructor_call( |
| 2939 | + constructor_symbol.symbol_expr(), arguments); |
| 2940 | + constructor_call.add_source_location() = location; |
| 2941 | + result.add(constructor_call); |
| 2942 | + if(needed_lazy_methods) |
2938 | 2943 | {
|
2939 |
| - error().source_location = location; |
2940 |
| - error() << "failed to zero-initialize return type" << eom; |
2941 |
| - throw 0; |
| 2944 | + needed_lazy_methods->add_needed_method(constructor_symbol.name); |
| 2945 | + needed_lazy_methods->add_needed_class(synthetic_class_name); |
2942 | 2946 | }
|
2943 |
| - return value; |
| 2947 | + |
| 2948 | + result_code = std::move(result); |
| 2949 | + |
| 2950 | + if(return_type.id() == ID_empty) |
| 2951 | + return {}; |
| 2952 | + else |
| 2953 | + return new_instance; |
2944 | 2954 | }
|
2945 | 2955 |
|
2946 | 2956 | void java_bytecode_convert_methodt::draw_edges_from_ret_to_jsr(
|
|
0 commit comments