Skip to content

Commit db1f3b5

Browse files
thk123Matthias Güdemann
thk123
authored and
Matthias Güdemann
committed
Adding tests for local lambdas
1 parent ba8b958 commit db1f3b5

File tree

3 files changed

+308
-0
lines changed

3 files changed

+308
-0
lines changed

unit/java_bytecode/java_bytecode_parser/java_bytecode_parse_lambda_method_table.cpp

+249
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,252 @@ SCENARIO(
276276
}
277277
}
278278
}
279+
SCENARIO(
280+
"lambda_method_handle_map with local lambdas",
281+
"[core][java_bytecode][java_bytecode_parse_lambda_method_handle]")
282+
{
283+
null_message_handlert message_handler;
284+
GIVEN("A method with local lambdas")
285+
{
286+
java_bytecode_parse_treet parse_tree;
287+
java_bytecode_parse(
288+
"./java_bytecode/java_bytecode_parser/lambda_examples/"
289+
"LocalLambdas.class",
290+
parse_tree,
291+
message_handler);
292+
WHEN("Parsing that class")
293+
{
294+
REQUIRE(parse_tree.loading_successful);
295+
const java_bytecode_parse_treet::classt parsed_class =
296+
parse_tree.parsed_class;
297+
REQUIRE(parsed_class.attribute_bootstrapmethods_read);
298+
REQUIRE(parsed_class.lambda_method_handle_map.size() == 12);
299+
300+
// Simple lambdas
301+
THEN(
302+
"There should be an entry for the lambda that has no parameters or "
303+
"returns and the method it references should have an appropriate "
304+
"descriptor")
305+
{
306+
const lambda_method_handlet &lambda_entry =
307+
require_parse_tree::require_lambda_entry_for_descriptor(
308+
parsed_class, "()V");
309+
310+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
311+
312+
const auto lambda_method =
313+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
314+
REQUIRE(id2string(lambda_method.descriptor) == "()V");
315+
}
316+
317+
// Parameter lambdas
318+
THEN(
319+
"There should be an entry for the lambda that takes parameters and the "
320+
"method it references should have an appropriate descriptor")
321+
{
322+
std::string descriptor = "(ILjava/lang/Object;LDummyGeneric;)V";
323+
const lambda_method_handlet &lambda_entry =
324+
require_parse_tree::require_lambda_entry_for_descriptor(
325+
parsed_class, descriptor);
326+
327+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
328+
329+
const auto lambda_method =
330+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
331+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
332+
}
333+
THEN(
334+
"There should be an entry for the lambda that takes array parameters "
335+
"and the method it references should have an appropriate descriptor")
336+
{
337+
std::string descriptor = "([I[Ljava/lang/Object;[LDummyGeneric;)V";
338+
const lambda_method_handlet &lambda_entry =
339+
require_parse_tree::require_lambda_entry_for_descriptor(
340+
parsed_class, descriptor);
341+
342+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
343+
344+
const auto lambda_method =
345+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
346+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
347+
}
348+
349+
// Return lambdas
350+
THEN(
351+
"There should be an entry for the lambda that returns a primitive and "
352+
"the method it references should have an appropriate descriptor")
353+
{
354+
std::string descriptor = "()I";
355+
const lambda_method_handlet &lambda_entry =
356+
require_parse_tree::require_lambda_entry_for_descriptor(
357+
parsed_class, descriptor);
358+
359+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
360+
361+
const auto lambda_method =
362+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
363+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
364+
}
365+
THEN(
366+
"There should be an entry for the lambda that returns a reference type "
367+
"and the method it references should have an appropriate descriptor")
368+
{
369+
std::string descriptor = "()Ljava/lang/Object;";
370+
const lambda_method_handlet &lambda_entry =
371+
require_parse_tree::require_lambda_entry_for_descriptor(
372+
parsed_class, descriptor);
373+
374+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
375+
376+
const auto lambda_method =
377+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
378+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
379+
}
380+
THEN(
381+
"There should be an entry for the lambda that returns a specialised "
382+
"generic type and the method it references should have an appropriate "
383+
"descriptor")
384+
{
385+
std::string descriptor = "()LDummyGeneric;";
386+
const lambda_method_handlet &lambda_entry =
387+
require_parse_tree::require_lambda_entry_for_descriptor(
388+
parsed_class, descriptor);
389+
390+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
391+
392+
const auto lambda_method =
393+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
394+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
395+
}
396+
397+
// Array returning lambdas
398+
THEN(
399+
"There should be an entry for the lambda that returns an array of "
400+
"primitives and the method it references should have an appropriate "
401+
"descriptor")
402+
{
403+
std::string descriptor = "()[I";
404+
const lambda_method_handlet &lambda_entry =
405+
require_parse_tree::require_lambda_entry_for_descriptor(
406+
parsed_class, descriptor);
407+
408+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
409+
410+
const auto lambda_method =
411+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
412+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
413+
}
414+
THEN(
415+
"There should be an entry for the lambda that returns an array of "
416+
"reference types and the method it references should have an "
417+
"appropriate descriptor")
418+
{
419+
std::string descriptor = "()[Ljava/lang/Object;";
420+
const lambda_method_handlet &lambda_entry =
421+
require_parse_tree::require_lambda_entry_for_descriptor(
422+
parsed_class, descriptor);
423+
424+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
425+
426+
const auto lambda_method =
427+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
428+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
429+
}
430+
THEN(
431+
"There should be an entry for the lambda that returns an array of "
432+
"specialised generic types and the method it references should have an "
433+
"appropriate descriptor")
434+
{
435+
std::string descriptor = "()[LDummyGeneric;";
436+
const lambda_method_handlet &lambda_entry =
437+
require_parse_tree::require_lambda_entry_for_descriptor(
438+
parsed_class, descriptor);
439+
440+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
441+
442+
const auto lambda_method =
443+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
444+
REQUIRE(id2string(lambda_method.descriptor) == descriptor);
445+
}
446+
447+
// Capturing lamdbas
448+
THEN(
449+
"There should be an entry for the lambda that returns a primitive "
450+
"local variable and the method it references should have an "
451+
"appropriate descriptor")
452+
{
453+
std::string descriptor = "()I";
454+
const lambda_method_handlet &lambda_entry =
455+
require_parse_tree::require_lambda_entry_for_descriptor(
456+
parsed_class, descriptor, 1);
457+
458+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
459+
460+
const auto lambda_method =
461+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
462+
// Note here the descriptor of the implementation is different - the
463+
// implementation requries the input to be passed in
464+
REQUIRE(id2string(lambda_method.descriptor) == "(I)I");
465+
466+
std::vector<require_parse_tree::expected_instructiont>
467+
expected_instructions{{"iload_0", {}}, {"ireturn", {}}};
468+
469+
require_parse_tree::require_instructions_match_expectation(
470+
expected_instructions, lambda_method.instructions);
471+
}
472+
THEN(
473+
"There should be an entry for the lambda that returns a reference type "
474+
"local variable and the method it references should have an "
475+
"appropriate descriptor")
476+
{
477+
// Since it is a local variable, the corresponding method takes the
478+
// captured variable as an input
479+
std::string descriptor = "()Ljava/lang/Object;";
480+
const lambda_method_handlet &lambda_entry =
481+
require_parse_tree::require_lambda_entry_for_descriptor(
482+
parsed_class, descriptor, 1);
483+
484+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
485+
486+
const auto lambda_method =
487+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
488+
REQUIRE(
489+
id2string(lambda_method.descriptor) ==
490+
"(Ljava/lang/Object;)Ljava/lang/Object;");
491+
492+
std::vector<require_parse_tree::expected_instructiont>
493+
expected_instructions{{"aload_0", {}}, {"areturn", {}}};
494+
495+
require_parse_tree::require_instructions_match_expectation(
496+
expected_instructions, lambda_method.instructions);
497+
}
498+
THEN(
499+
"There should be an entry for the lambda that returns a specialised "
500+
"generic type local variable and the method it references should have "
501+
"an appropriate descriptor")
502+
{
503+
// Since it is a local variable, the corresponding method takes the
504+
// captured variable as an input
505+
std::string descriptor = "()LDummyGeneric;";
506+
const lambda_method_handlet &lambda_entry =
507+
require_parse_tree::require_lambda_entry_for_descriptor(
508+
parsed_class, descriptor, 1);
509+
510+
const irep_idt &lambda_impl_name = lambda_entry.lambda_method_name;
511+
512+
const java_bytecode_parse_treet::methodt &lambda_method =
513+
require_parse_tree::require_method(parsed_class, lambda_impl_name);
514+
REQUIRE(
515+
id2string(lambda_method.descriptor) ==
516+
"(LDummyGeneric;)LDummyGeneric;");
517+
518+
// since just returning the parameter, nothing to put on the stack
519+
std::vector<require_parse_tree::expected_instructiont>
520+
expected_instructions{{"aload_0", {}}, {"areturn", {}}};
521+
522+
require_parse_tree::require_instructions_match_expectation(
523+
expected_instructions, lambda_method.instructions);
524+
}
525+
}
526+
}
527+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
public class LocalLambdas {
2+
public static void test() {
3+
int localPrimitive = 5;
4+
Object localReference = null;
5+
DummyGeneric<Integer> localSpecalisedGeneric = null;
6+
7+
// Declare some local lambdas
8+
SimpleLambda simpleLambda = () -> { /*NOP*/ };
9+
10+
ParameterLambda paramLambda =
11+
(int primitive, Object reference, DummyGeneric<Integer> specalisedGeneric) -> {};
12+
ArrayParameterLambda arrayParamLambda =
13+
(int[] primitive, Object[] reference, DummyGeneric<Integer>[] specalisedGeneric) -> {};
14+
15+
ReturningLambdaPrimitive returnPrimitiveLambda = () -> {
16+
return 1;
17+
};
18+
ReturningLambdaReference returnReferenceLambda = () -> {
19+
return null;
20+
};
21+
ReturningLambdaSpecalisedGeneric returningSpecalisedGenericLambda = () -> {
22+
return null;
23+
};
24+
25+
ReturningLambdaPrimitiveArray returnPrimitiveArrayLambda = () -> {
26+
return null;
27+
};
28+
ReturningLambdaReferenceArray returnReferenceArrayLambda = () -> {
29+
return null;
30+
};
31+
ReturningLambdaSpecalisedGenericArray returningSpecalisedGenericArrayLambda = () -> {
32+
return null;
33+
};
34+
35+
ReturningLambdaPrimitive returnPrimitiveLambdaCapture = () -> {
36+
return localPrimitive;
37+
};
38+
ReturningLambdaReference returnReferenceLambdaCapture = () -> {
39+
return localReference;
40+
};
41+
ReturningLambdaSpecalisedGeneric returningSpecalisedGenericLambdaCapture = () -> {
42+
return localSpecalisedGeneric;
43+
};
44+
45+
simpleLambda.Execute();
46+
paramLambda.Execute(4, null, null);
47+
arrayParamLambda.Execute(null, null, null);
48+
returnPrimitiveLambda.Execute();
49+
returnReferenceLambda.Execute();
50+
returningSpecalisedGenericLambda.Execute();
51+
returnPrimitiveArrayLambda.Execute();
52+
returnReferenceArrayLambda.Execute();
53+
returningSpecalisedGenericArrayLambda.Execute();
54+
55+
returnPrimitiveLambdaCapture.Execute();
56+
returnReferenceLambdaCapture.Execute();
57+
returningSpecalisedGenericLambdaCapture.Execute();
58+
}
59+
}

0 commit comments

Comments
 (0)