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