Skip to content

Commit 5cbb758

Browse files
author
Thomas Kiley
authored
Merge pull request diffblue#1937 from svorenova/lambda_tg2711
[TG-2478] Make Bootstrap methods available in method/instruction conversion
2 parents 8cfd9bf + 212da75 commit 5cbb758

File tree

87 files changed

+803
-267
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+803
-267
lines changed

src/java_bytecode/java_bytecode_convert_class.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,18 @@ void java_bytecode_convert_classt::convert(const classt &c)
310310
}
311311
}
312312

313+
// now do lambda method handles (bootstrap methods)
314+
for(const auto &lambda_entry : c.lambda_method_handle_map)
315+
{
316+
// if the handle is of unknown type, we still need to store it to preserve
317+
// the correct indexing (invokedynamic instructions will retrieve
318+
// method handles by index)
319+
lambda_entry.second.is_unknown_handle()
320+
? class_type.add_unknown_lambda_method_handle()
321+
: class_type.add_lambda_method_handle(
322+
"java::" + id2string(lambda_entry.second.lambda_method_ref));
323+
}
324+
313325
// produce class symbol
314326
symbolt new_symbol;
315327
new_symbol.base_name=c.name;

src/java_bytecode/java_bytecode_convert_method.cpp

+39-3
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,25 @@ code_typet member_type_lazy(
306306
return to_code_type(member_type_from_descriptor);
307307
}
308308

309+
/// Retrieves the symbol of the lambda method associated with the given
310+
/// lambda method handle (bootstrap method).
311+
/// \param lambda_method_handles Vector of lambda method handles (bootstrap
312+
/// methods) of the class where the lambda is called
313+
/// \param index Index of the lambda method handle in the vector
314+
/// \return Symbol of the lambda method if the method handle does not have an
315+
/// unknown type
316+
optionalt<symbolt> java_bytecode_convert_methodt::get_lambda_method_symbol(
317+
const java_class_typet::java_lambda_method_handlest &lambda_method_handles,
318+
const size_t &index)
319+
{
320+
const symbol_exprt &lambda_method_handle = lambda_method_handles.at(index);
321+
// If the lambda method handle has an unknown type, it does not refer to
322+
// any symbol (it is a symbol expression with empty identifier)
323+
if(!lambda_method_handle.get_identifier().empty())
324+
return symbol_table.lookup_ref(lambda_method_handle.get_identifier());
325+
return {};
326+
}
327+
309328
/// This creates a method symbol in the symtab, but doesn't actually perform
310329
/// method conversion just yet. The caller should call
311330
/// java_bytecode_convert_method later to give the symbol/method a body.
@@ -555,7 +574,11 @@ void java_bytecode_convert_methodt::convert(
555574
current_method=method_symbol.name;
556575
method_has_this=code_type.has_this();
557576
if((!m.is_abstract) && (!m.is_native))
558-
method_symbol.value=convert_instructions(m, code_type, method_symbol.name);
577+
method_symbol.value = convert_instructions(
578+
m,
579+
code_type,
580+
method_symbol.name,
581+
to_java_class_type(class_symbol.type).lambda_method_handles());
559582
}
560583

561584
const bytecode_infot &java_bytecode_convert_methodt::get_bytecode_info(
@@ -926,7 +949,8 @@ static unsigned get_bytecode_type_width(const typet &ty)
926949
codet java_bytecode_convert_methodt::convert_instructions(
927950
const methodt &method,
928951
const code_typet &method_type,
929-
const irep_idt &method_name)
952+
const irep_idt &method_name,
953+
const java_class_typet::java_lambda_method_handlest &lambda_method_handles)
930954
{
931955
const instructionst &instructions=method.instructions;
932956

@@ -1211,7 +1235,19 @@ codet java_bytecode_convert_methodt::convert_instructions(
12111235
else if(statement=="invokedynamic")
12121236
{
12131237
// not used in Java
1214-
code_typet &code_type=to_code_type(arg0.type());
1238+
code_typet &code_type = to_code_type(arg0.type());
1239+
1240+
const optionalt<symbolt> &lambda_method_symbol = get_lambda_method_symbol(
1241+
lambda_method_handles,
1242+
code_type.get_int(ID_java_lambda_method_handle_index));
1243+
if(lambda_method_symbol.has_value())
1244+
debug() << "Converting invokedynamic for lambda: "
1245+
<< lambda_method_symbol.value().name << eom;
1246+
else
1247+
debug() << "Converting invokedynamic for lambda with unknown handle "
1248+
"type"
1249+
<< eom;
1250+
12151251
const code_typet::parameterst &parameters(code_type.parameters());
12161252

12171253
pop(parameters.size());

src/java_bytecode/java_bytecode_convert_method_class.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -235,13 +235,18 @@ class java_bytecode_convert_methodt:public messaget
235235
const address_mapt &amap,
236236
bool allow_merge=true);
237237

238+
optionalt<symbolt> get_lambda_method_symbol(
239+
const java_class_typet::java_lambda_method_handlest &lambda_method_handles,
240+
const size_t &index);
241+
238242
// conversion
239243
void convert(const symbolt &class_symbol, const methodt &);
240244

241245
codet convert_instructions(
242246
const methodt &,
243247
const code_typet &,
244-
const irep_idt &);
248+
const irep_idt &,
249+
const java_class_typet::java_lambda_method_handlest &);
245250

246251
const bytecode_infot &get_bytecode_info(const irep_idt &statement);
247252

src/java_bytecode/java_bytecode_parse_tree.h

+6
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ class java_bytecode_parse_treet
193193
public:
194194
method_handle_typet handle_type;
195195
irep_idt lambda_method_name;
196+
irep_idt lambda_method_ref;
196197
irep_idt interface_type;
197198
irep_idt method_type;
198199
u2_valuest u2_values;
@@ -208,6 +209,11 @@ class java_bytecode_parse_treet
208209
lambda_method_handle.u2_values = std::move(params);
209210
return lambda_method_handle;
210211
}
212+
213+
bool is_unknown_handle() const
214+
{
215+
return handle_type == method_handle_typet::UNKNOWN_HANDLE;
216+
}
211217
};
212218

213219
// TODO(tkiley): This map shouldn't be interacted with directly (instead

src/java_bytecode/java_bytecode_parser.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,7 @@ void java_bytecode_parsert::rconstant_pool()
843843
it->expr.id("invokedynamic");
844844
const pool_entryt &nameandtype_entry=pool_entry(it->ref2);
845845
typet type=type_entry(nameandtype_entry.ref2);
846+
type.set(ID_java_lambda_method_handle_index, it->ref1);
846847
it->expr.type()=type;
847848
}
848849
break;
@@ -1776,9 +1777,9 @@ java_bytecode_parsert::parse_method_handle(const method_handle_infot &entry)
17761777
const name_and_type_infot &name_and_type =
17771778
ref_entry.get_name_and_type(pool_entry_lambda);
17781779

1779-
const std::string method_name =
1780+
const std::string method_ref =
17801781
class_entry.get_name(pool_entry_lambda) + "." +
1781-
name_and_type.get_name(pool_entry_lambda) +
1782+
name_and_type.get_name(pool_entry_lambda) + ':' +
17821783
name_and_type.get_descriptor(pool_entry_lambda);
17831784

17841785
lambda_method_handlet lambda_method_handle;
@@ -1791,6 +1792,7 @@ java_bytecode_parsert::parse_method_handle(const method_handle_infot &entry)
17911792
// "new" when it is a class variable, instantiated in <init>
17921793
lambda_method_handle.lambda_method_name =
17931794
name_and_type.get_name(pool_entry_lambda);
1795+
lambda_method_handle.lambda_method_ref = method_ref;
17941796
lambda_method_handle.handle_type =
17951797
method_handle_typet::LAMBDA_METHOD_HANDLE;
17961798

src/java_bytecode/java_types.h

+25
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Author: Daniel Kroening, [email protected]
1717
#include <util/std_types.h>
1818
#include <util/c_types.h>
1919
#include <util/optional.h>
20+
#include <util/std_expr.h>
2021

2122
class java_class_typet:public class_typet
2223
{
@@ -30,6 +31,30 @@ class java_class_typet:public class_typet
3031
{
3132
return set(ID_access, access);
3233
}
34+
35+
typedef std::vector<symbol_exprt> java_lambda_method_handlest;
36+
37+
const java_lambda_method_handlest &lambda_method_handles() const
38+
{
39+
return (const java_lambda_method_handlest &)find(
40+
ID_java_lambda_method_handles)
41+
.get_sub();
42+
}
43+
44+
java_lambda_method_handlest &lambda_method_handles()
45+
{
46+
return (java_lambda_method_handlest &)add(ID_java_lambda_method_handles)
47+
.get_sub();
48+
}
49+
50+
void add_lambda_method_handle(const irep_idt &identifier)
51+
{
52+
lambda_method_handles().emplace_back(identifier);
53+
}
54+
void add_unknown_lambda_method_handle()
55+
{
56+
lambda_method_handles().emplace_back();
57+
}
3358
};
3459

3560
inline const java_class_typet &to_java_class_type(const typet &type)

src/util/irep_ids.def

+2
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,8 @@ IREP_ID_TWO(C_java_generic_symbol, #java_generic_symbol)
836836
IREP_ID_TWO(generic_types, #generic_types)
837837
IREP_ID_TWO(implicit_generic_types, #implicit_generic_types)
838838
IREP_ID_TWO(type_variables, #type_variables)
839+
IREP_ID_TWO(java_lambda_method_handle_index, lambda_method_handle_index)
840+
IREP_ID_TWO(java_lambda_method_handles, lambda_method_handles)
839841
IREP_ID_ONE(havoc_object)
840842
IREP_ID_TWO(overflow_shl, overflow-shl)
841843
IREP_ID_TWO(C_no_initialization_required, #no_initialization_required)

unit/Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ SRC += unit_tests.cpp \
2323
java_bytecode/java_bytecode_convert_class/convert_abstract_class.cpp \
2424
java_bytecode/java_bytecode_parse_generics/parse_generic_class.cpp \
2525
java_bytecode/java_object_factory/gen_nondet_string_init.cpp \
26+
java_bytecode/java_bytecode_parse_lambdas/java_bytecode_parse_lambda_method_table.cpp \
27+
java_bytecode/java_bytecode_parse_lambdas/java_bytecode_convert_class_lambda_method_handles.cpp \
2628
miniBDD_new.cpp \
2729
java_bytecode/java_string_library_preprocess/convert_exprt_to_string_exprt.cpp \
2830
java_bytecode/java_utils_test.cpp \

unit/java_bytecode/ci_lazy_methods/lazy_load_lambdas.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ SCENARIO(
1818
{
1919
const symbol_tablet symbol_table = load_java_class_lazy(
2020
"LocalLambdas",
21-
"./java_bytecode/java_bytecode_parser/lambda_examples/",
21+
"./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/",
2222
"LocalLambdas.test");
2323

2424
THEN("Then the lambdas should be loaded")
@@ -68,7 +68,7 @@ SCENARIO(
6868
{
6969
const symbol_tablet symbol_table = load_java_class_lazy(
7070
"MemberLambdas",
71-
"./java_bytecode/java_bytecode_parser/lambda_examples/",
71+
"./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/",
7272
"MemberLambdas.test");
7373

7474
THEN("Then the lambdas should be loaded")
@@ -117,7 +117,7 @@ SCENARIO(
117117
{
118118
const symbol_tablet symbol_table = load_java_class_lazy(
119119
"StaticLambdas",
120-
"./java_bytecode/java_bytecode_parser/lambda_examples/",
120+
"./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/",
121121
"StaticLambdas.test");
122122

123123
THEN("Then the lambdas should be loaded")
@@ -166,7 +166,7 @@ SCENARIO(
166166
{
167167
const symbol_tablet symbol_table = load_java_class_lazy(
168168
"OuterMemberLambdas$Inner",
169-
"./java_bytecode/java_bytecode_parser/lambda_examples/",
169+
"./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/",
170170
"OuterMemberLambdas$Inner.test");
171171

172172
THEN("Then the lambdas should be loaded")
@@ -192,7 +192,7 @@ SCENARIO(
192192
{
193193
const symbol_tablet symbol_table = load_java_class_lazy(
194194
"ExternalLambdaAccessor",
195-
"./java_bytecode/java_bytecode_parser/lambda_examples/",
195+
"./java_bytecode/java_bytecode_parse_lambdas/lambda_examples/",
196196
"ExternalLambdaAccessor.test");
197197

198198
THEN("Then the lambdas should be loaded")

0 commit comments

Comments
 (0)