CBMC
lambda_synthesis.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Java lambda code synthesis
4 
5 Author: Diffblue Ltd.
6 
7 \*******************************************************************/
8 
11 
12 #include "lambda_synthesis.h"
13 
14 #include "jar_file.h"
18 #include "java_types.h"
19 #include "java_utils.h"
20 #include "synthetic_methods_map.h"
21 
22 #include <util/message.h>
23 #include <util/namespace.h>
24 #include <util/symbol_table.h>
25 
26 #include <string.h>
27 
28 static std::string escape_symbol_special_chars(std::string input)
29 {
30  for(auto &c : input)
31  {
32  if(c == '$' || c == ':' || c == '.')
33  c = '_';
34  }
35  return input;
36 }
37 
39  const irep_idt &method_identifier,
40  std::size_t instruction_address)
41 {
42  return "java::lambda_synthetic_class$" +
44  id2string(strip_java_namespace_prefix(method_identifier))) +
45  "$" + std::to_string(instruction_address);
46 }
47 
57  const symbol_table_baset &symbol_table,
58  const java_class_typet::java_lambda_method_handlest &lambda_method_handles,
59  const size_t index)
60 {
61  // Check if we don't have enough bootstrap methods to satisfy the requested
62  // lambda. This could happen if we fail to parse one of the methods, or if
63  // the class type is partly or entirely synthetic, such as the types created
64  // internally by the string solver.
65  if(index >= lambda_method_handles.size())
66  return {};
67  const auto &lambda_method_handle = lambda_method_handles.at(index);
68  // If the lambda method handle has an unknown type, it does not refer to
69  // any symbol (it has an empty identifier)
70  if(
71  lambda_method_handle.get_handle_kind() !=
73  return lambda_method_handle;
74  return {};
75 }
76 
79  const symbol_tablet &symbol_table,
80  const irep_idt &method_identifier,
81  const java_method_typet &dynamic_method_type)
82 {
83  const namespacet ns{symbol_table};
84  const auto &method_symbol = ns.lookup(method_identifier);
85  const auto &declaring_class_symbol =
86  ns.lookup(*declaring_class(method_symbol));
87 
88  const auto &class_type = to_java_class_type(declaring_class_symbol.type);
89  const auto &lambda_method_handles = class_type.lambda_method_handles();
90  auto lambda_handle_index =
91  dynamic_method_type.get_int(ID_java_lambda_method_handle_index);
93  symbol_table, lambda_method_handles, lambda_handle_index);
94 }
95 
96 class no_unique_unimplemented_method_exceptiont : public std::exception
97 {
98 public:
99  explicit no_unique_unimplemented_method_exceptiont(const std::string &s)
100  : message(s)
101  {
102  }
103  const std::string message;
104 };
105 
107 {
109  const java_class_typet::methodt *a,
110  const java_class_typet::methodt *b) const
111  {
112  return a->get_base_name() == b->get_base_name()
113  ? (a->get_descriptor() == b->get_descriptor()
114  ? 0
115  : a->get_descriptor() < b->get_descriptor())
116  : a->get_base_name() < b->get_base_name();
117  }
118 };
119 
122 typedef std::map<
124  bool,
127 
136 get_interface_methods(const irep_idt &interface_id, const namespacet &ns)
137 {
138  static const irep_idt jlo = "java::java.lang.Object";
139  // Terminate recursion at Object; any other base of an interface must
140  // itself be an interface.
141  if(jlo == interface_id)
142  return {};
143 
144  const java_class_typet &interface =
145  to_java_class_type(ns.lookup(interface_id).type);
146 
147  if(interface.get_is_stub())
148  {
150  "produces a type that inherits the stub type " + id2string(interface_id));
151  }
152 
154 
155  // First accumulate definitions from child types:
156  for(const auto &base : interface.bases())
157  {
158  const methods_by_name_and_descriptort base_methods =
159  get_interface_methods(base.type().get_identifier(), ns);
160  for(const auto &base_method : base_methods)
161  {
162  if(base_method.second)
163  {
164  // Any base definition fills any abstract definition from another base:
165  all_methods[base_method.first] = true;
166  }
167  else
168  {
169  // An abstract method incoming from a base falls to any existing
170  // definition, so only insert if not present:
171  all_methods.emplace(base_method.first, false);
172  }
173  }
174  }
175 
176  // Now insert defintions from this class:
177  for(const auto &method : interface.methods())
178  {
179  static const irep_idt equals = "equals";
180  static const irep_idt equals_descriptor = "(Ljava/lang/Object;)Z";
181  static const irep_idt hashCode = "hashCode";
182  static const irep_idt hashCode_descriptor = "()I";
183  if(
184  (method.get_base_name() == equals &&
185  method.get_descriptor() == equals_descriptor) ||
186  (method.get_base_name() == hashCode &&
187  method.get_descriptor() == hashCode_descriptor))
188  {
189  // Ignore any uses of functions that are certainly defined on
190  // java.lang.Object-- even if explicitly made abstract, they can't be the
191  // implemented method of a functional interface.
192  continue;
193  }
194 
195  // Note unlike inherited definitions, an abstract definition here *does*
196  // wipe out a non-abstract definition (i.e. a default method) from a parent
197  // type.
198  all_methods[&method] =
199  !ns.lookup(method.get_name()).type.get_bool(ID_C_abstract);
200  }
201 
202  return all_methods;
203 }
204 
206  const symbol_tablet &symbol_table,
207  const struct_tag_typet &functional_interface_tag,
208  const irep_idt &method_identifier,
209  const int instruction_address,
210  const messaget &log)
211 {
212  const namespacet ns{symbol_table};
213  try
214  {
215  const methods_by_name_and_descriptort all_methods =
216  get_interface_methods(functional_interface_tag.get_identifier(), ns);
217 
218  const java_class_typet::methodt *method_and_descriptor_to_implement =
219  nullptr;
220 
221  for(const auto &entry : all_methods)
222  {
223  if(!entry.second)
224  {
225  if(method_and_descriptor_to_implement != nullptr)
226  {
228  "produces a type with at least two unimplemented methods");
229  }
230  method_and_descriptor_to_implement = entry.first;
231  }
232  }
233 
234  if(!method_and_descriptor_to_implement)
235  {
237  "produces a type with no unimplemented methods");
238  }
239  return method_and_descriptor_to_implement;
240  }
242  {
243  log.debug() << "ignoring invokedynamic at " << method_identifier
244  << " address " << instruction_address << " with type "
245  << functional_interface_tag.get_identifier() << " which "
246  << e.message << "." << messaget::eom;
247  return {};
248  }
249 }
250 
252  const irep_idt &synthetic_class_name,
254  const struct_tag_typet &functional_interface_tag,
255  const java_method_typet &dynamic_method_type)
256 {
257  java_class_typet synthetic_class_type;
258  // Tag = name without 'java::' prefix, matching the convention used by
259  // java_bytecode_convert_class.cpp
260  synthetic_class_type.set_tag(
261  strip_java_namespace_prefix(synthetic_class_name));
262  synthetic_class_type.set_name(synthetic_class_name);
263  synthetic_class_type.set_synthetic(true);
264  synthetic_class_type.set(ID_java_lambda_method_handle, lambda_method_handle);
265  struct_tag_typet base_tag("java::java.lang.Object");
266  synthetic_class_type.add_base(base_tag);
267  synthetic_class_type.add_base(functional_interface_tag);
268 
269  // Add the class fields:
270 
271  {
272  java_class_typet::componentt base_field;
273  const irep_idt base_field_name("@java.lang.Object");
274  base_field.set_name(base_field_name);
275  base_field.set_base_name(base_field_name);
276  base_field.set_pretty_name(base_field_name);
277  base_field.set_access(ID_private);
278  base_field.type() = base_tag;
279  synthetic_class_type.components().emplace_back(std::move(base_field));
280 
281  std::size_t field_idx = 0;
282  for(const auto &param : dynamic_method_type.parameters())
283  {
284  irep_idt field_basename = "capture_" + std::to_string(field_idx++);
285 
287  new_field.set_name(field_basename);
288  new_field.set_base_name(field_basename);
289  new_field.set_pretty_name(field_basename);
290  new_field.set_access(ID_private);
291  new_field.type() = param.type();
292  synthetic_class_type.components().emplace_back(std::move(new_field));
293  }
294  }
295 
296  symbolt synthetic_class_symbol = type_symbolt{synthetic_class_type};
297  synthetic_class_symbol.name = synthetic_class_name;
298  synthetic_class_symbol.mode = ID_java;
299  return synthetic_class_symbol;
300 }
301 
303  synthetic_methods_mapt &synthetic_methods,
304  const irep_idt &synthetic_class_name,
305  java_method_typet constructor_type) // dynamic_method_type
306 {
308  irep_idt constructor_name = id2string(synthetic_class_name) + ".<init>";
309  constructor_symbol.name = constructor_name;
311  constructor_symbol.base_name = "<init>";
312  constructor_symbol.mode = ID_java;
313 
314  synthetic_methods[constructor_name] =
316 
317  constructor_type.set_is_constructor();
318  constructor_type.return_type() = empty_typet();
319 
320  size_t field_idx = 0;
321  for(auto &param : constructor_type.parameters())
322  {
323  irep_idt param_basename = "param_" + std::to_string(field_idx++);
324  param.set_base_name(param_basename);
325  param.set_identifier(
326  id2string(constructor_name) + "::" + id2string(param_basename));
327  }
328 
329  java_method_typet::parametert constructor_this_param(
330  java_reference_type(struct_tag_typet(synthetic_class_name)));
331  constructor_this_param.set_this();
332  constructor_this_param.set_base_name("this");
333  constructor_this_param.set_identifier(id2string(constructor_name) + "::this");
334 
335  constructor_type.parameters().insert(
336  constructor_type.parameters().begin(), constructor_this_param);
337 
338  constructor_symbol.type = constructor_type;
339  set_declaring_class(constructor_symbol, synthetic_class_name);
340  return constructor_symbol;
341 }
342 
344  synthetic_methods_mapt &synthetic_methods,
345  const java_class_typet::methodt &method_to_implement,
346  const irep_idt &synthetic_class_name)
347 {
348  const std::string implemented_method_name =
349  id2string(synthetic_class_name) + "." +
350  id2string(method_to_implement.get_base_name()) + ":" +
351  id2string(method_to_implement.get_descriptor());
352 
354  implemented_method_symbol.name = implemented_method_name;
355  synthetic_methods[implemented_method_symbol.name] =
358  implemented_method_symbol.base_name = method_to_implement.get_base_name();
360  implemented_method_symbol.type = method_to_implement.type();
361  auto &implemented_method_type = to_code_type(implemented_method_symbol.type);
362  implemented_method_type.parameters()[0].type() =
363  java_reference_type(struct_tag_typet(synthetic_class_name));
364 
365  size_t field_idx = 0;
366  for(auto &param : implemented_method_type.parameters())
367  {
368  irep_idt param_basename =
369  field_idx == 0 ? "this" : "param_" + std::to_string(field_idx);
370  param.set_base_name(param_basename);
371  param.set_identifier(
372  id2string(implemented_method_name) + "::" + id2string(param_basename));
373 
374  ++field_idx;
375  }
376 
377  set_declaring_class(implemented_method_symbol, synthetic_class_name);
379 }
380 
381 // invokedynamic will be called with operands that should be stored in a
382 // synthetic object implementing the interface type that it returns. For
383 // example, "invokedynamic f(a, b, c) -> MyInterface" should result in the
384 // creation of the synthetic class:
385 // public class SyntheticCapture implements MyInterface {
386 // private int a;
387 // private float b;
388 // private Other c;
389 // public SyntheticCapture(int a, float b, Other c) {
390 // this.a = a; this.b = b; this.c = c;
391 // }
392 // public void myInterfaceMethod(int d) {
393 // f(a, b, c, d);
394 // }
395 // }
396 // This method just creates the outline; the methods will be populated on
397 // demand via java_bytecode_languaget::convert_lazy_method.
398 
399 // Check that we understand the lambda method handle; if we don't then
400 // we will not create a synthetic class at all, and the corresponding
401 // invoke instruction will return null when eventually converted by
402 // java_bytecode_convert_method.
404  const irep_idt &method_identifier,
406  symbol_tablet &symbol_table,
407  synthetic_methods_mapt &synthetic_methods,
408  message_handlert &message_handler)
409 {
410  const messaget log{message_handler};
411 
412  for(const auto &instruction : instructions)
413  {
414  if(strcmp(bytecode_info[instruction.bytecode].mnemonic, "invokedynamic"))
415  continue;
416  const auto &dynamic_method_type =
417  to_java_method_type(instruction.args.at(0).type());
418  const auto lambda_handle = lambda_method_handle(
419  symbol_table, method_identifier, dynamic_method_type);
420  if(!lambda_handle)
421  {
422  log.debug() << "ignoring invokedynamic at " << method_identifier
423  << " address " << instruction.address
424  << " with unknown handle type" << messaget::eom;
425  continue;
426  }
427  const auto &functional_interface_tag = to_struct_tag_type(
428  to_java_reference_type(dynamic_method_type.return_type()).subtype());
429  const auto unimplemented_method = try_get_unique_unimplemented_method(
430  symbol_table,
431  functional_interface_tag,
432  method_identifier,
433  instruction.address,
434  log);
435  if(!unimplemented_method)
436  continue;
437  log.debug() << "identified invokedynamic at " << method_identifier
438  << " address " << instruction.address << " for lambda: "
439  << lambda_handle->get_lambda_method_identifier()
440  << messaget::eom;
441  const irep_idt synthetic_class_name =
442  lambda_synthetic_class_name(method_identifier, instruction.address);
443  symbol_table.add(constructor_symbol(
444  synthetic_methods, synthetic_class_name, dynamic_method_type));
445  symbol_table.add(implemented_method_symbol(
446  synthetic_methods, *unimplemented_method, synthetic_class_name));
447  symbol_table.add(synthetic_class_symbol(
448  synthetic_class_name,
449  *lambda_handle,
450  functional_interface_tag,
451  dynamic_method_type));
452  }
453 }
454 
456  const irep_idt &identifier,
457  const irep_idt &base_name,
458  const irep_idt &pretty_name,
459  const typet &type,
460  const irep_idt &declaring_class,
461  symbol_table_baset &symbol_table,
462  message_handlert &log)
463 {
464  const auto *existing_symbol = symbol_table.lookup(identifier);
465  if(existing_symbol)
466  return *existing_symbol;
467 
469  identifier,
470  base_name,
471  pretty_name,
472  type,
474  symbol_table,
475  log);
476  return symbol_table.lookup_ref(identifier);
477 }
478 
480  const irep_idt &function_id,
481  symbol_table_baset &symbol_table,
482  message_handlert &message_handler)
483 {
484  code_blockt result;
485  namespacet ns(symbol_table);
486 
487  const symbolt &function_symbol = ns.lookup(function_id);
488  const auto &parameters = to_code_type(function_symbol.type).parameters();
489 
490  const symbolt &class_symbol = ns.lookup(*declaring_class(function_symbol));
491  const class_typet &class_type = to_class_type(class_symbol.type);
492 
493  const symbol_exprt this_param(
494  parameters.at(0).get_identifier(), parameters.at(0).type());
495  const dereference_exprt deref_this(this_param);
496 
497  // Call super-constructor (always java.lang.Object):
498  const irep_idt jlo("java::java.lang.Object");
499  const irep_idt jlo_constructor(id2string(jlo) + ".<init>:()V");
500  const auto jlo_reference = java_reference_type(struct_tag_typet(jlo));
501  code_typet::parametert jlo_this_param{jlo_reference};
502  jlo_this_param.set_this();
503 
504  java_method_typet jlo_constructor_type(
505  code_typet::parameterst{jlo_this_param}, empty_typet());
506  const auto &jlo_constructor_symbol = get_or_create_method_symbol(
507  jlo_constructor,
508  "<init>",
509  jlo_constructor,
510  jlo_constructor_type,
511  jlo,
512  symbol_table,
513  message_handler);
514  code_function_callt super_constructor_call(
515  jlo_constructor_symbol.symbol_expr(),
516  code_function_callt::argumentst{typecast_exprt(this_param, jlo_reference)});
517  result.add(super_constructor_call);
518 
519  // Store captured parameters:
520  auto field_iterator = std::next(class_type.components().begin());
521  for(const auto &parameter : parameters)
522  {
523  // Give the parameter its symbol:
524  parameter_symbolt param_symbol;
525  param_symbol.name = parameter.get_identifier();
526  param_symbol.base_name = parameter.get_base_name();
527  param_symbol.mode = ID_java;
528  param_symbol.type = parameter.type();
529  symbol_table.add(param_symbol);
530 
531  if(parameter.get_this())
532  continue;
533 
534  code_frontend_assignt assign_field(
535  member_exprt(deref_this, field_iterator->get_name(), parameter.type()),
536  symbol_exprt(parameter.get_identifier(), parameter.type()));
537  result.add(assign_field);
538 
539  ++field_iterator;
540  }
541 
542  return std::move(result);
543 }
544 
546  const irep_idt &function_id,
547  const irep_idt &basename,
548  const typet &type,
549  symbol_table_baset &symbol_table,
550  code_blockt &method)
551 {
552  irep_idt new_var_name = id2string(function_id) + "::" + id2string(basename);
553  auxiliary_symbolt new_instance_var_symbol;
554  new_instance_var_symbol.name = new_var_name;
555  new_instance_var_symbol.base_name = basename;
556  new_instance_var_symbol.mode = ID_java;
557  new_instance_var_symbol.type = type;
558  bool add_failed = symbol_table.add(new_instance_var_symbol);
559  POSTCONDITION(!add_failed);
560  symbol_exprt new_instance_var = new_instance_var_symbol.symbol_expr();
561  method.add(code_declt{new_instance_var});
562 
563  return new_instance_var;
564 }
565 
577  const irep_idt &function_id,
578  const symbolt &lambda_method_symbol,
579  symbol_table_baset &symbol_table,
580  code_blockt &result)
581 {
582  // We must instantiate the object, then call the requested constructor
583  const auto &method_type = to_code_type(lambda_method_symbol.type);
584  INVARIANT(
585  method_type.get_bool(ID_constructor),
586  "REF_NewInvokeSpecial lambda must refer to a constructor");
587  const auto &created_type = method_type.parameters().at(0).type();
588  irep_idt created_class =
589  to_struct_tag_type(to_reference_type(created_type).base_type())
590  .get_identifier();
591 
592  // Call static init if it exists:
593  irep_idt static_init_name = clinit_wrapper_name(created_class);
594  if(const auto *static_init_symbol = symbol_table.lookup(static_init_name))
595  {
596  result.add(code_function_callt{static_init_symbol->symbol_expr(), {}});
597  }
598 
599  // Make a local to hold the new instance:
600  symbol_exprt new_instance_var = create_and_declare_local(
601  function_id,
602  "newinvokespecial_instance",
603  created_type,
604  symbol_table,
605  result);
606 
607  // Instantiate the object:
608  side_effect_exprt java_new_expr(ID_java_new, created_type, {});
609  result.add(code_frontend_assignt{new_instance_var, java_new_expr});
610 
611  return new_instance_var;
612 }
613 
616 static optionalt<irep_idt>
617 get_unboxing_method(const pointer_typet &maybe_boxed_type)
618 {
619  const irep_idt &boxed_type_id =
620  to_struct_tag_type(maybe_boxed_type.base_type()).get_identifier();
621  const java_boxed_type_infot *boxed_type_info =
622  get_boxed_type_info_by_name(boxed_type_id);
623  return boxed_type_info ? boxed_type_info->unboxing_function_name
625 }
626 
631  const symbolt &function_symbol,
632  const symbol_tablet &symbol_table)
633 {
634  const auto &method_type = to_java_method_type(function_symbol.type);
635  if(!method_type.has_this())
636  return function_symbol.symbol_expr();
637  const irep_idt &declared_on_class_id =
639  to_pointer_type(method_type.get_this()->type()).base_type())
640  .get_identifier();
641  const auto &this_symbol = symbol_table.lookup_ref(declared_on_class_id);
642  if(to_java_class_type(this_symbol.type).get_final())
643  return function_symbol.symbol_expr();
644 
645  // Neither final nor static; make a class_method_descriptor_exprt that will
646  // trigger remove_virtual_functions to produce a virtual dispatch table:
647 
648  const std::string &function_name = id2string(function_symbol.name);
649  const auto method_name_start_idx = function_name.rfind('.');
650  const irep_idt mangled_method_name =
651  function_name.substr(method_name_start_idx + 1);
652 
653  return class_method_descriptor_exprt{function_symbol.type,
654  mangled_method_name,
655  declared_on_class_id,
656  function_symbol.base_name};
657 }
658 
689  exprt expr,
690  const typet &required_type,
691  code_blockt &code_block,
692  symbol_table_baset &symbol_table,
693  const irep_idt &function_id,
694  const std::string &role)
695 {
696  const typet &original_type = expr.type();
697  const bool original_is_pointer = can_cast_type<pointer_typet>(original_type);
698  const bool required_is_pointer = can_cast_type<pointer_typet>(required_type);
699 
700  if(original_is_pointer == required_is_pointer)
701  {
702  return expr;
703  }
704 
705  // One is a pointer, the other a primitive -- box or unbox as necessary, and
706  // check the types are consistent:
707 
708  const auto *primitive_type_info = get_java_primitive_type_info(
709  original_is_pointer ? required_type : original_type);
710  INVARIANT(
711  primitive_type_info != nullptr,
712  "A Java non-pointer type involved in a type disagreement should"
713  " be a primitive");
714 
715  const irep_idt fresh_local_name =
716  role + (original_is_pointer ? "_unboxed" : "_boxed");
717 
718  const symbol_exprt fresh_local = create_and_declare_local(
719  function_id, fresh_local_name, required_type, symbol_table, code_block);
720 
721  const irep_idt transform_function_id =
722  original_is_pointer
724  to_pointer_type(original_type)) // Use static type if known
725  .value_or(primitive_type_info->unboxing_function_name)
726  : primitive_type_info->boxed_type_factory_method;
727 
728  const symbolt &transform_function_symbol =
729  symbol_table.lookup_ref(transform_function_id);
730 
731  const typet &transform_function_param_type =
732  to_code_type(transform_function_symbol.type).parameters()[0].type();
733  const exprt cast_expr =
734  typecast_exprt::conditional_cast(expr, transform_function_param_type);
735 
736  code_block.add(code_function_callt{
737  fresh_local,
738  make_function_expr(transform_function_symbol, symbol_table),
739  {expr}});
740 
741  return std::move(fresh_local);
742 }
743 
748  exprt expr,
749  const typet &required_type,
750  code_blockt &code_block,
751  symbol_table_baset &symbol_table,
752  const irep_idt &function_id,
753  const std::string &role)
754 {
757  expr, required_type, code_block, symbol_table, function_id, role),
758  required_type);
759 }
760 
778  const irep_idt &function_id,
779  symbol_table_baset &symbol_table,
780  message_handlert &message_handler)
781 {
782  // Call the bound method with the capture parameters, then the actual
783  // parameters. Note one of the capture params might be the `this` parameter
784  // of a virtual call -- that depends on whether the callee is a static or an
785  // instance method.
786 
787  code_blockt result;
788  namespacet ns(symbol_table);
789 
790  const symbolt &function_symbol = ns.lookup(function_id);
791  const auto &function_type = to_code_type(function_symbol.type);
792  const auto &parameters = function_type.parameters();
793 
794  const symbolt &class_symbol = ns.lookup(*declaring_class(function_symbol));
795  const java_class_typet &class_type = to_java_class_type(class_symbol.type);
796 
797  const symbol_exprt this_param(
798  parameters.at(0).get_identifier(), parameters.at(0).type());
799  const dereference_exprt deref_this(this_param);
800 
801  code_function_callt::argumentst lambda_method_args;
802  for(const auto &field : class_type.components())
803  {
804  if(field.get_name() == "@java.lang.Object")
805  continue;
806  lambda_method_args.push_back(
807  member_exprt(deref_this, field.get_name(), field.type()));
808  }
809 
810  for(const auto &parameter : parameters)
811  {
812  // Give the parameter its symbol:
813  parameter_symbolt param_symbol;
814  param_symbol.name = parameter.get_identifier();
815  param_symbol.base_name = parameter.get_base_name();
816  param_symbol.mode = ID_java;
817  param_symbol.type = parameter.type();
818  symbol_table.add(param_symbol);
819 
820  if(parameter.get_this())
821  continue;
822 
823  lambda_method_args.push_back(param_symbol.symbol_expr());
824  }
825 
826  const auto &lambda_method_handle =
828  class_type.find(ID_java_lambda_method_handle));
829 
830  const auto &lambda_method_symbol =
831  ns.lookup(lambda_method_handle.get_lambda_method_identifier());
832  const auto handle_type = lambda_method_handle.get_handle_kind();
833  const auto is_constructor_lambda =
834  handle_type ==
836  const auto use_virtual_dispatch =
837  handle_type ==
839 
840  if(is_constructor_lambda)
841  {
842  auto new_instance_var = instantiate_new_object(
843  function_id, lambda_method_symbol, symbol_table, result);
844 
845  // Prepend the newly created object to the lambda arg list:
846  lambda_method_args.insert(lambda_method_args.begin(), new_instance_var);
847  }
848 
849  const auto &lambda_method_descriptor =
850  lambda_method_handle.get_lambda_method_descriptor();
851  exprt callee;
852  if(use_virtual_dispatch)
853  callee = lambda_method_descriptor;
854  else
855  callee = lambda_method_symbol.symbol_expr();
856 
857  // Adjust boxing if required:
858  const code_typet &callee_type = to_code_type(lambda_method_symbol.type);
859  const auto &callee_parameters = callee_type.parameters();
860  const auto &callee_return_type = callee_type.return_type();
861  INVARIANT(
862  callee_parameters.size() == lambda_method_args.size(),
863  "should have args for every parameter");
864  for(unsigned i = 0; i < callee_parameters.size(); ++i)
865  {
866  lambda_method_args[i] = adjust_type_if_necessary(
867  std::move(lambda_method_args[i]),
868  callee_parameters[i].type(),
869  result,
870  symbol_table,
871  function_id,
872  "param" + std::to_string(i));
873  }
874 
875  if(function_type.return_type() != empty_typet() && !is_constructor_lambda)
876  {
877  symbol_exprt result_local = create_and_declare_local(
878  function_id, "return_value", callee_return_type, symbol_table, result);
879  result.add(code_function_callt(result_local, callee, lambda_method_args));
880  exprt adjusted_local = adjust_type_if_necessary(
881  result_local,
882  function_type.return_type(),
883  result,
884  symbol_table,
885  function_id,
886  "retval");
887  result.add(code_returnt{adjusted_local});
888  }
889  else
890  {
891  result.add(code_function_callt(callee, lambda_method_args));
892  }
893 
894  if(is_constructor_lambda)
895  {
896  // Return the newly-created object.
898  lambda_method_args.at(0), function_type.return_type())});
899  }
900 
901  return std::move(result);
902 }
messaget
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:154
tag_typet::get_identifier
const irep_idt & get_identifier() const
Definition: std_types.h:410
java_static_initializers.h
struct_union_typet::components
const componentst & components() const
Definition: std_types.h:147
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
code_blockt
A codet representing sequential composition of program statements.
Definition: std_code.h:129
typecast_exprt::conditional_cast
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2025
symbol_tablet
The symbol table.
Definition: symbol_table.h:13
java_class_typet::componentt
Definition: java_types.h:199
symbol_table_baset::lookup_ref
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
Definition: symbol_table_base.h:104
class_typet
Class type.
Definition: std_types.h:324
invokedynamic_synthetic_method
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.
Definition: lambda_synthesis.cpp:777
bytecode_infot::mnemonic
const char * mnemonic
Definition: bytecode_info.h:46
java_class_typet::method_handle_kindt::LAMBDA_VIRTUAL_METHOD_HANDLE
@ LAMBDA_VIRTUAL_METHOD_HANDLE
Virtual call to the given interface or method.
java_reference_type
reference_typet java_reference_type(const typet &subtype)
Definition: java_types.cpp:88
java_class_typet::set_synthetic
void set_synthetic(bool synthetic)
marks class synthetic
Definition: java_types.h:434
set_declaring_class
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.
Definition: java_utils.cpp:577
typet
The type of an expression, extends irept.
Definition: type.h:28
code_typet::parameterst
std::vector< parametert > parameterst
Definition: std_types.h:541
java_bytecode_parse_treet::methodt::instructionst
std::vector< instructiont > instructionst
Definition: java_bytecode_parse_tree.h:91
to_class_type
const class_typet & to_class_type(const typet &type)
Cast a typet to a class_typet.
Definition: std_types.h:381
irept::find
const irept & find(const irep_idt &name) const
Definition: irep.cpp:106
symbolt::type
typet type
Type of symbol.
Definition: symbol.h:31
dereference_exprt
Operator to dereference a pointer.
Definition: pointer_expr.h:659
compare_base_name_and_descriptort
Definition: lambda_synthesis.cpp:106
lambda_method_handle
static optionalt< java_class_typet::java_lambda_method_handlet > lambda_method_handle(const symbol_tablet &symbol_table, const irep_idt &method_identifier, const java_method_typet &dynamic_method_type)
Definition: lambda_synthesis.cpp:78
code_typet::parametert::set_identifier
void set_identifier(const irep_idt &identifier)
Definition: std_types.h:580
struct_typet::add_base
void add_base(const struct_tag_typet &base)
Add a base class/struct.
Definition: std_types.cpp:98
get_interface_methods
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...
Definition: lambda_synthesis.cpp:136
create_invokedynamic_synthetic_classes
void create_invokedynamic_synthetic_classes(const irep_idt &method_identifier, const java_bytecode_parse_treet::methodt::instructionst &instructions, symbol_tablet &symbol_table, synthetic_methods_mapt &synthetic_methods, message_handlert &message_handler)
Definition: lambda_synthesis.cpp:403
declaring_class
optionalt< irep_idt > declaring_class(const symbolt &symbol)
Gets the identifier of the class which declared a given symbol.
Definition: java_utils.cpp:571
java_class_typet::methodt
Definition: java_types.h:240
code_declt
A goto_instruction_codet representing the declaration of a local variable.
Definition: goto_instruction_code.h:204
synthetic_method_typet::INVOKEDYNAMIC_CAPTURE_CONSTRUCTOR
@ INVOKEDYNAMIC_CAPTURE_CONSTRUCTOR
A generated constructor for a class capturing the parameters of an invokedynamic instruction.
synthetic_method_typet::INVOKEDYNAMIC_METHOD
@ INVOKEDYNAMIC_METHOD
A generated method for a class capturing the parameters of an invokedynamic instruction.
exprt
Base class for all expressions.
Definition: expr.h:55
jar_file.h
symbolt::base_name
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:46
struct_tag_typet
A struct tag type, i.e., struct_typet with an identifier.
Definition: std_types.h:448
no_unique_unimplemented_method_exceptiont::message
const std::string message
Definition: lambda_synthesis.cpp:103
create_and_declare_local
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)
Definition: lambda_synthesis.cpp:545
to_string
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
Definition: string_constraint.cpp:58
messaget::eom
static eomt eom
Definition: message.h:297
auxiliary_symbolt
Internally generated symbol table entry.
Definition: symbol.h:146
synthetic_methods_mapt
std::unordered_map< irep_idt, synthetic_method_typet > synthetic_methods_mapt
Maps method names on to a synthetic method kind.
Definition: synthetic_methods_map.h:57
symbol_exprt
Expression to hold a symbol (variable)
Definition: std_expr.h:112
namespace.h
can_cast_type< pointer_typet >
bool can_cast_type< pointer_typet >(const typet &type)
Check whether a reference to a typet is a pointer_typet.
Definition: pointer_expr.h:66
symbolt::pretty_name
irep_idt pretty_name
Language-specific display name.
Definition: symbol.h:52
java_class_typet
Definition: java_types.h:196
class_method_descriptor_exprt
An expression describing a method on a class.
Definition: std_expr.h:3440
java_class_typet::java_lambda_method_handlet
Represents a lambda call to a method.
Definition: java_types.h:481
strip_java_namespace_prefix
irep_idt strip_java_namespace_prefix(const irep_idt &to_strip)
Strip java:: prefix from given identifier.
Definition: java_utils.cpp:410
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
methods_by_name_and_descriptort
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....
Definition: lambda_synthesis.cpp:126
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
java_class_typet::methodt::type
const java_method_typet & type() const
Definition: java_types.h:250
namespacet::lookup
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:138
code_function_callt
goto_instruction_codet representation of a function call statement.
Definition: goto_instruction_code.h:271
java_boxed_type_infot
Return type for get_boxed_type_info_by_name.
Definition: java_utils.h:53
to_code_type
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:744
symbolt::mode
irep_idt mode
Language mode.
Definition: symbol.h:49
java_reference_typet::subtype
struct_tag_typet & subtype()
Definition: java_types.h:612
empty_typet
The empty type.
Definition: std_types.h:50
no_unique_unimplemented_method_exceptiont::no_unique_unimplemented_method_exceptiont
no_unique_unimplemented_method_exceptiont(const std::string &s)
Definition: lambda_synthesis.cpp:99
id2string
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
struct_union_typet::set_tag
void set_tag(const irep_idt &tag)
Definition: std_types.h:169
java_class_typet::java_lambda_method_handlest
std::vector< java_lambda_method_handlet > java_lambda_method_handlest
Definition: java_types.h:515
code_typet::set_is_constructor
void set_is_constructor()
Definition: std_types.h:690
irept::set
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:420
java_bytecode_parse_tree.h
symbol_table_baset
The symbol table base class interface.
Definition: symbol_table_base.h:21
to_java_reference_type
const java_reference_typet & to_java_reference_type(const typet &type)
Definition: java_types.h:630
symbolt::symbol_expr
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
java_class_typet::method_handle_kindt::LAMBDA_CONSTRUCTOR_HANDLE
@ LAMBDA_CONSTRUCTOR_HANDLE
Instantiate the needed type then call a constructor.
to_pointer_type
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:79
get_unboxing_method
static optionalt< 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.
Definition: lambda_synthesis.cpp:617
to_reference_type
const reference_typet & to_reference_type(const typet &type)
Cast a typet to a reference_typet.
Definition: pointer_expr.h:148
synthetic_class_symbol
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)
Definition: lambda_synthesis.cpp:251
code_frontend_assignt
A codet representing an assignment in the program.
Definition: std_code.h:23
code_typet
Base type of functions.
Definition: std_types.h:538
message_handlert
Definition: message.h:27
create_method_stub_symbol
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)
Definition: java_bytecode_convert_method.cpp:92
java_bytecode_convert_method.h
java_class_typet::method_handle_kindt::UNKNOWN_HANDLE
@ UNKNOWN_HANDLE
Can't be called.
to_struct_tag_type
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:474
code_function_callt::argumentst
exprt::operandst argumentst
Definition: goto_instruction_code.h:281
code_blockt::add
void add(const codet &code)
Definition: std_code.h:168
code_typet::parameters
const parameterst & parameters() const
Definition: std_types.h:655
java_class_typet::get_final
bool get_final() const
Definition: java_types.h:383
optionalt
nonstd::optional< T > optionalt
Definition: optional.h:35
try_get_unique_unimplemented_method
static const java_class_typet::methodt * try_get_unique_unimplemented_method(const symbol_tablet &symbol_table, const struct_tag_typet &functional_interface_tag, const irep_idt &method_identifier, const int instruction_address, const messaget &log)
Definition: lambda_synthesis.cpp:205
escape_symbol_special_chars
static std::string escape_symbol_special_chars(std::string input)
Definition: lambda_synthesis.cpp:28
code_typet::parametert::set_base_name
void set_base_name(const irep_idt &name)
Definition: std_types.h:585
box_or_unbox_type_if_necessary
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 ...
Definition: lambda_synthesis.cpp:688
code_typet::parametert::set_this
void set_this()
Definition: std_types.h:605
no_unique_unimplemented_method_exceptiont
Definition: lambda_synthesis.cpp:96
invokedynamic_synthetic_constructor
codet invokedynamic_synthetic_constructor(const irep_idt &function_id, symbol_table_baset &symbol_table, message_handlert &message_handler)
Create invokedynamic synthetic constructor.
Definition: lambda_synthesis.cpp:479
adjust_type_if_necessary
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.
Definition: lambda_synthesis.cpp:747
symbol_table_baset::add
bool add(const symbolt &symbol)
Add a new symbol to the symbol table.
Definition: symbol_table_base.cpp:18
member_exprt
Extract member of struct or union.
Definition: std_expr.h:2793
lambda_synthesis.h
java_class_typet::components
const componentst & components() const
Definition: java_types.h:224
java_class_typet::methodt::get_descriptor
const irep_idt & get_descriptor() const
Gets the method's descriptor – the mangled form of its type.
Definition: java_types.h:286
POSTCONDITION
#define POSTCONDITION(CONDITION)
Definition: invariant.h:479
make_function_expr
exprt make_function_expr(const symbolt &function_symbol, const symbol_tablet &symbol_table)
Produce a class_method_descriptor_exprt or symbol_exprt for function_symbol depending on whether virt...
Definition: lambda_synthesis.cpp:630
code_returnt
goto_instruction_codet representation of a "return from a function" statement.
Definition: goto_instruction_code.h:494
symbolt
Symbol table entry.
Definition: symbol.h:27
compare_base_name_and_descriptort::operator()
int operator()(const java_class_typet::methodt *a, const java_class_typet::methodt *b) const
Definition: lambda_synthesis.cpp:108
pointer_typet::base_type
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
irept::get_int
signed int get_int(const irep_idt &name) const
Definition: irep.cpp:63
code_typet::parametert
Definition: std_types.h:555
java_class_typet::set_name
void set_name(const irep_idt &name)
Set the name of the struct, which can be used to look up its symbol in the symbol table.
Definition: java_types.h:564
type_symbolt
Symbol table entry describing a data type.
Definition: symbol.h:132
clinit_wrapper_name
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...
Definition: java_static_initializers.cpp:73
java_boxed_type_infot::unboxing_function_name
const irep_idt unboxing_function_name
Name of the function defined on the boxed type that returns the boxed value.
Definition: java_utils.h:57
symbol_table_baset::lookup
const symbolt * lookup(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
Definition: symbol_table_base.h:95
code_typet::return_type
const typet & return_type() const
Definition: std_types.h:645
constructor_symbol
static symbolt constructor_symbol(synthetic_methods_mapt &synthetic_methods, const irep_idt &synthetic_class_name, java_method_typet constructor_type)
Definition: lambda_synthesis.cpp:302
get_or_create_method_symbol
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)
Definition: lambda_synthesis.cpp:455
to_java_class_type
const java_class_typet & to_java_class_type(const typet &type)
Definition: java_types.h:582
messaget::debug
mstreamt & debug() const
Definition: message.h:429
parameter_symbolt
Symbol table entry of function parameter.
Definition: symbol.h:170
get_boxed_type_info_by_name
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.
Definition: java_utils.cpp:35
java_types.h
instantiate_new_object
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).
Definition: lambda_synthesis.cpp:576
get_lambda_method_handle
static optionalt< 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...
Definition: lambda_synthesis.cpp:56
to_java_method_type
const java_method_typet & to_java_method_type(const typet &type)
Definition: java_types.h:184
symbol_table.h
Author: Diffblue Ltd.
pointer_typet
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
Definition: pointer_expr.h:23
bytecode_info
struct bytecode_infot const bytecode_info[]
Definition: bytecode_info.cpp:16
message.h
implemented_method_symbol
static symbolt implemented_method_symbol(synthetic_methods_mapt &synthetic_methods, const java_class_typet::methodt &method_to_implement, const irep_idt &synthetic_class_name)
Definition: lambda_synthesis.cpp:343
java_utils.h
java_method_typet
Definition: java_types.h:100
lambda_synthetic_class_name
irep_idt lambda_synthetic_class_name(const irep_idt &method_identifier, std::size_t instruction_address)
Definition: lambda_synthesis.cpp:38
get_java_primitive_type_info
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.
Definition: java_utils.cpp:62
synthetic_methods_map.h
symbolt::name
irep_idt name
The unique identifier.
Definition: symbol.h:40
side_effect_exprt
An expression containing a side effect.
Definition: std_code.h:1449
validation_modet::INVARIANT
@ INVARIANT
codet
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:28