Skip to content

Lambda lazy loading [TG-2485] #1918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 239 additions & 0 deletions unit/java_bytecode/ci_lazy_methods/lazy_load_lambdas.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
/*******************************************************************\

Module: Unit tests for parsing generic classes

Author: DiffBlue Limited. All rights reserved.

\*******************************************************************/

#include <testing-utils/catch.hpp>
#include <testing-utils/load_java_class.h>
#include <testing-utils/require_symbol.h>

SCENARIO(
"Lazy load lambda methods",
"[core][java_bytecode][ci_lazy_methods][lambdas][!mayfail]")
{
GIVEN("A class with some locally declared lambdas")
{
const symbol_tablet symbol_table = load_java_class_lazy(
"LocalLambdas",
"./java_bytecode/java_bytecode_parser/lambda_examples/",
"LocalLambdas.test");

THEN("Then the lambdas should be loaded")
{
std::string lambda_name_prefix = "java::LocalLambdas.lambda$test$";
require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "0:()V");

require_symbol::require_symbol_exists(
symbol_table,
lambda_name_prefix + "1:(ILjava/lang/Object;LDummyGeneric;)V");

require_symbol::require_symbol_exists(
symbol_table,
lambda_name_prefix + "2:([I[Ljava/lang/Object;[LDummyGeneric;)V");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "3:()I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "4:()Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "5:()LDummyGeneric;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "6:()[I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "7:()[Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "8:()[LDummyGeneric;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "9:(I)I");

require_symbol::require_symbol_exists(
symbol_table,
lambda_name_prefix + "10:(Ljava/lang/Object;)Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "11:(LDummyGeneric;)LDummyGeneric;");
}
}
GIVEN("A class with some member lambdas")
{
const symbol_tablet symbol_table = load_java_class_lazy(
"MemberLambdas",
"./java_bytecode/java_bytecode_parser/lambda_examples/",
"MemberLambdas.test");

THEN("Then the lambdas should be loaded")
{
std::string lambda_name_prefix = "java::MemberLambdas.lambda$new$";
require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "0:()V");

require_symbol::require_symbol_exists(
symbol_table,
lambda_name_prefix + "1:(ILjava/lang/Object;LDummyGeneric;)V");

require_symbol::require_symbol_exists(
symbol_table,
lambda_name_prefix + "2:([I[Ljava/lang/Object;[LDummyGeneric;)V");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "3:()I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "4:()Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "5:()LDummyGeneric;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "6:()[I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "7:()[Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "8:()[LDummyGeneric;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "9:()I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "10:()Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "11:()LDummyGeneric;");
}
}
GIVEN("A class with some static lambdas")
{
const symbol_tablet symbol_table = load_java_class_lazy(
"StaticLambdas",
"./java_bytecode/java_bytecode_parser/lambda_examples/",
"StaticLambdas.test");

THEN("Then the lambdas should be loaded")
{
std::string lambda_name_prefix = "java::StaticLambdas.lambda$static$";
require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "0:()V");

require_symbol::require_symbol_exists(
symbol_table,
lambda_name_prefix + "1:(ILjava/lang/Object;LDummyGeneric;)V");

require_symbol::require_symbol_exists(
symbol_table,
lambda_name_prefix + "2:([I[Ljava/lang/Object;[LDummyGeneric;)V");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "3:()I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "4:()Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "5:()LDummyGeneric;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "6:()[I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "7:()[Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "8:()[LDummyGeneric;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "9:()I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "10:()Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "11:()LDummyGeneric;");
}
}
GIVEN("A class with some outer member lambdas")
{
const symbol_tablet symbol_table = load_java_class_lazy(
"OuterMemberLambdas$Inner",
"./java_bytecode/java_bytecode_parser/lambda_examples/",
"OuterMemberLambdas$Inner.test");

THEN("Then the lambdas should be loaded")
{
std::string lambda_name_prefix =
"java::OuterMemberLambdas$Inner.lambda$new$";

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "0:()I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "1:()Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "2:()LDummyGeneric;");
}
}
}

SCENARIO(
"Lazy load lambda methods in seperate class",
"[core][java_bytecode][ci_lazy_methods][lambdas][!mayfail]")
{
const symbol_tablet symbol_table = load_java_class_lazy(
"ExternalLambdaAccessor",
"./java_bytecode/java_bytecode_parser/lambda_examples/",
"ExternalLambdaAccessor.test");

THEN("Then the lambdas should be loaded")
{
std::string lambda_name_prefix = "java::ExternalLambdas.lambda$new$";
require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "0:()V");

require_symbol::require_symbol_exists(
symbol_table,
lambda_name_prefix + "1:(ILjava/lang/Object;LDummyGeneric;)V");

require_symbol::require_symbol_exists(
symbol_table,
lambda_name_prefix + "2:([I[Ljava/lang/Object;[LDummyGeneric;)V");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "3:()I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "4:()Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "5:()LDummyGeneric;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "6:()[I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "7:()[Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "8:()[LDummyGeneric;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "9:()I");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "10:()Ljava/lang/Object;");

require_symbol::require_symbol_exists(
symbol_table, lambda_name_prefix + "11:()LDummyGeneric;");
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class ExternalLambdas
{
int memberPrimitive;
Object memberReference;
DummyGeneric<Integer> memberSpecalisedGeneric;

public SimpleLambda simpleLambda = () -> { /*NOP*/ };
public ParameterLambda paramLambda = (int primitive, Object reference, DummyGeneric<Integer> specalisedGeneric) -> {};
public ArrayParameterLambda arrayParamLambda = (int[] primitive, Object[] reference, DummyGeneric<Integer>[] specalisedGeneric) -> {};
public ReturningLambdaPrimitive returnPrimitiveLambda = () -> { return 1; };
public ReturningLambdaReference returnReferenceLambda = () -> { return null; };
public ReturningLambdaSpecalisedGeneric returningSpecalisedGenericLambda = () -> { return null; };
public ReturningLambdaPrimitiveArray returnPrimitiveArrayLambda = () -> { return null; };
public ReturningLambdaReferenceArray returnReferenceArrayLambda = () -> { return null; };
public ReturningLambdaSpecalisedGenericArray returningSpecalisedGenericArrayLambda = () -> { return null; };
public ReturningLambdaPrimitive returnPrimitiveLambdaCapture = () -> { return memberPrimitive; };
public ReturningLambdaReference returnReferenceLambdaCapture = () -> { return memberReference; };
public ReturningLambdaSpecalisedGeneric returningSpecalisedGenericLambdaCapture = () -> { return memberSpecalisedGeneric; };
}

public class ExternalLambdaAccessor
{
public static void test()
{
ExternalLambdas e = new ExternalLambdas();
e.simpleLambda.Execute();
e.paramLambda.Execute(4, null, null);
e.arrayParamLambda.Execute(null, null, null);
e.returnPrimitiveLambda.Execute();
e.returnReferenceLambda.Execute();
e.returningSpecalisedGenericLambda.Execute();
e.returnPrimitiveArrayLambda.Execute();
e.returnReferenceArrayLambda.Execute();
e.returningSpecalisedGenericArrayLambda.Execute();
e.returnPrimitiveLambdaCapture.Execute();
e.returnReferenceLambdaCapture.Execute();
e.returningSpecalisedGenericLambdaCapture.Execute();
}
}
Binary file not shown.
23 changes: 23 additions & 0 deletions unit/testing-utils/require_symbol.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*******************************************************************\

Module: Unit test utilities

Author: DiffBlue Limited. All rights reserved.

\*******************************************************************/

#include "require_symbol.h"
#include "catch.hpp"

/// Verify whether a given identifier is found in the symbol table and return it
/// \param symbol_table: The symbol table to look in
/// \param symbol_identifier: The name of the symbol
const symbolt &require_symbol::require_symbol_exists(
const symbol_tablet &symbol_table,
const irep_idt &symbol_identifier)
{
const symbolt *found_symbol = symbol_table.lookup(symbol_identifier);
INFO("Looking for symbol: " + id2string(symbol_identifier));
REQUIRE(found_symbol != nullptr);
return *found_symbol;
}
26 changes: 26 additions & 0 deletions unit/testing-utils/require_symbol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************\

Module: Unit test utilities

Author: DiffBlue Limited. All rights reserved.

\*******************************************************************/

#ifndef CPROVER_TESTING_UTILS_REQUIRE_SYMBOL_H
#define CPROVER_TESTING_UTILS_REQUIRE_SYMBOL_H

#include <util/symbol.h>
#include <util/symbol_table.h>

/// \file
/// Helper functions for getting symbols from the symbol table during unit tests

// NOLINTNEXTLINE(readability/namespace)
namespace require_symbol
{
const symbolt &require_symbol_exists(
const symbol_tablet &symbol_table,
const irep_idt &symbol_identifier);
}

#endif // CPROVER_TESTING_UTILS_REQUIRE_SYMBOL_H