Skip to content

Commit 624cc91

Browse files
author
svorenova
committed
Use the map of parameter-type pairs to specialize generics
1 parent 3111255 commit 624cc91

7 files changed

+150
-18
lines changed

src/java_bytecode/ci_lazy_methods.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,10 @@ void ci_lazy_methodst::initialize_all_needed_classes_from_pointer(
322322
{
323323
initialize_needed_classes_from_pointer(pointer_type, ns, needed_lazy_methods);
324324

325-
const pointer_typet &subbed_pointer_type=
326-
pointer_type_selector.convert_pointer_type(pointer_type, ns);
325+
// TODO we should be passing here a map that maps generic parameters
326+
// to concrete types in the current context TG-2664
327+
const pointer_typet &subbed_pointer_type =
328+
pointer_type_selector.convert_pointer_type(pointer_type, {}, ns);
327329

328330
if(subbed_pointer_type!=pointer_type)
329331
{

src/java_bytecode/java_object_factory.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -753,18 +753,19 @@ void java_object_factoryt::gen_nondet_pointer_init(
753753
const update_in_placet &update_in_place)
754754
{
755755
PRECONDITION(expr.type().id()==ID_pointer);
756-
const pointer_typet &replacement_pointer_type=
757-
pointer_type_selector.convert_pointer_type(pointer_type, ns);
756+
const pointer_typet &replacement_pointer_type =
757+
pointer_type_selector.convert_pointer_type(
758+
pointer_type, generic_parameter_specialization_map, ns);
758759

759760
// If we are changing the pointer, we generate code for creating a pointer
760761
// to the substituted type instead
761-
if(replacement_pointer_type!=pointer_type)
762+
// TODO if we are comparing array types we need to compare their element
763+
// types. this is for now done by implementing equality function especially
764+
// for java types, technical debt TG-2707
765+
if(!equal_java_types(replacement_pointer_type, pointer_type))
762766
{
763-
const symbol_exprt real_pointer_symbol=gen_nondet_subtype_pointer_init(
764-
assignments,
765-
alloc_type,
766-
replacement_pointer_type,
767-
depth);
767+
const symbol_exprt real_pointer_symbol = gen_nondet_subtype_pointer_init(
768+
assignments, alloc_type, replacement_pointer_type, depth);
768769

769770
// Having created a pointer to object of type replacement_pointer_type
770771
// we now assign it back to the original pointer with a cast

src/java_bytecode/java_object_factory.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,6 @@ exprt object_factory(
107107
allocation_typet alloc_type,
108108
const source_locationt &location);
109109

110-
typedef std::unordered_map<irep_idt, std::stack<reference_typet>,
111-
irep_id_hash> generic_parameter_specialization_mapt;
112-
113110
enum class update_in_placet
114111
{
115112
NO_UPDATE_IN_PLACE,

src/java_bytecode/java_types.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,37 @@ bool is_valid_java_array(const struct_typet &type)
713713
data_component_valid;
714714
}
715715

716+
/// Compares the types, including checking element types if both types are
717+
/// arrays.
718+
/// \param type1 First type to compare
719+
/// \param type2 Second type to compare
720+
/// \return True if the types are equal, including elemnt types if they are
721+
/// both arrays
722+
bool equal_java_types(const typet &type1, const typet &type2)
723+
{
724+
bool arrays_with_same_element_type = true;
725+
if(
726+
type1.id() == ID_pointer && type2.id() == ID_pointer &&
727+
type1.subtype().id() == ID_symbol && type2.subtype().id() == ID_symbol)
728+
{
729+
const symbol_typet &subtype_symbol1 = to_symbol_type(type1.subtype());
730+
const symbol_typet &subtype_symbol2 = to_symbol_type(type2.subtype());
731+
if(
732+
subtype_symbol1.get_identifier() == subtype_symbol2.get_identifier() &&
733+
is_java_array_tag(subtype_symbol1.get_identifier()))
734+
{
735+
const typet &array_element_type1 =
736+
java_array_element_type(subtype_symbol1);
737+
const typet &array_element_type2 =
738+
java_array_element_type(subtype_symbol2);
739+
740+
arrays_with_same_element_type =
741+
equal_java_types(array_element_type1, array_element_type2);
742+
}
743+
}
744+
return (type1 == type2 && arrays_with_same_element_type);
745+
}
746+
716747
void get_dependencies_from_generic_parameters_rec(
717748
const typet &t,
718749
std::set<irep_idt> &refs)

src/java_bytecode/java_types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ size_t find_closing_semi_colon_for_reference_type(
9090
bool is_java_array_tag(const irep_idt &tag);
9191
bool is_valid_java_array(const struct_typet &);
9292

93+
bool equal_java_types(const typet &type1, const typet &type2);
94+
9395
/// Class to hold a Java generic type parameter (also called type variable),
9496
/// e.g., `T` in `List<T>`.
9597
/// The bound can specify type requirements.

src/java_bytecode/select_pointer_type.cpp

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,101 @@
1111
/// classes to concrete versions).
1212

1313
#include "select_pointer_type.h"
14+
#include "java_types.h"
1415
#include <util/std_types.h>
1516

1617
/// Select what type should be used for a given pointer type. For the base class
1718
/// we just use the supplied type. Derived classes can override this behaviour
18-
/// to provide more sophisticated type selection
19+
/// to provide more sophisticated type selection. Generic parameters are
20+
/// replaced with their concrete type.
1921
/// \param pointer_type: The pointer type replace
22+
/// \param generic_parameter_specialization_map map of types for all generic
23+
/// parameters in the current scope
2024
/// \return A pointer type where the subtype may have been modified
2125
pointer_typet select_pointer_typet::convert_pointer_type(
22-
const pointer_typet &pointer_type, const namespacet &ns) const
26+
const pointer_typet &pointer_type,
27+
const generic_parameter_specialization_mapt
28+
&generic_parameter_specialization_map,
29+
const namespacet &ns) const
2330
{
24-
return pointer_type;
31+
// if we have a map of generic parameters -> types and the pointer is
32+
// a generic parameter, specialize it with concrete types
33+
if(!generic_parameter_specialization_map.empty())
34+
{
35+
return specialize_generics(
36+
pointer_type, generic_parameter_specialization_map);
37+
}
38+
else
39+
{
40+
return pointer_type;
41+
}
42+
}
43+
44+
/// Specialize generic parameters in a pointer type based on the current map
45+
/// of parameters -> types. We specialize generics if the pointer is a java
46+
/// generic parameter or an array with generic parameters (java generic types
47+
/// are specialized recursively, their concrete types are already stored in
48+
/// the map and will be retrieved when needed e.g., to initialize fields).
49+
/// Example:
50+
/// - generic type: T
51+
/// - map: T -> U; U -> String
52+
/// - result: String
53+
///
54+
/// - generic type: T[]
55+
/// - map: T -> U; U -> String
56+
/// - result: String
57+
/// \param pointer_type pointer to be specialized
58+
/// \param generic_parameter_specialization_map map of types for all generic
59+
/// parameters in the current scope
60+
/// \return pointer type where generic parameters are replaced with concrete
61+
/// types, if set in the current scope
62+
pointer_typet select_pointer_typet::specialize_generics(
63+
const pointer_typet &pointer_type,
64+
const generic_parameter_specialization_mapt
65+
&generic_parameter_specialization_map) const
66+
{
67+
if(is_java_generic_parameter(pointer_type))
68+
{
69+
const java_generic_parametert &parameter =
70+
to_java_generic_parameter(pointer_type);
71+
const irep_idt &parameter_name = parameter.get_name();
72+
if(generic_parameter_specialization_map.count(parameter_name) == 0)
73+
{
74+
// this means that the generic pointer_type has not been specialized
75+
// in the current context (e.g., the method under test is generic);
76+
// we return the pointer_type itself which is basically a pointer to
77+
// its upper bound
78+
return pointer_type;
79+
}
80+
const pointer_typet &type =
81+
generic_parameter_specialization_map.find(parameter_name)->second.top();
82+
83+
// generic parameters can be adopted from outer classes or superclasses so
84+
// we may need to search for the concrete type recursively
85+
return is_java_generic_parameter(type)
86+
? specialize_generics(
87+
to_java_generic_parameter(type),
88+
generic_parameter_specialization_map)
89+
: type;
90+
}
91+
else if(pointer_type.subtype().id() == ID_symbol)
92+
{
93+
// if the pointer is an array, recursively specialize its element type
94+
const symbol_typet &array_subtype = to_symbol_type(pointer_type.subtype());
95+
if(is_java_array_tag(array_subtype.get_identifier()))
96+
{
97+
const typet &array_element_type = java_array_element_type(array_subtype);
98+
if(array_element_type.id() == ID_pointer)
99+
{
100+
const pointer_typet &new_array_type = specialize_generics(
101+
to_pointer_type(array_element_type),
102+
generic_parameter_specialization_map);
103+
104+
pointer_typet replacement_array_type = java_array_type('a');
105+
replacement_array_type.subtype().set(ID_C_element_type, new_array_type);
106+
return replacement_array_type;
107+
}
108+
}
109+
}
110+
return pointer_type;
25111
}

src/java_bytecode/select_pointer_type.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,28 @@
1313
/// classes to concrete versions).
1414

1515
#include <util/std_types.h>
16+
#include <stack>
17+
#include "java_types.h"
18+
19+
typedef std::unordered_map<irep_idt, std::stack<reference_typet>, irep_id_hash>
20+
generic_parameter_specialization_mapt;
1621

1722
class namespacet;
1823

1924
class select_pointer_typet
2025
{
2126
public:
22-
virtual ~select_pointer_typet()=default;
27+
virtual ~select_pointer_typet() = default;
2328
virtual pointer_typet convert_pointer_type(
24-
const pointer_typet &pointer_type, const namespacet &ns) const;
29+
const pointer_typet &pointer_type,
30+
const generic_parameter_specialization_mapt
31+
&generic_parameter_specialization_map,
32+
const namespacet &ns) const;
33+
34+
pointer_typet specialize_generics(
35+
const pointer_typet &pointer_type,
36+
const generic_parameter_specialization_mapt
37+
&generic_parameter_specialization_map) const;
2538
};
2639

2740
#endif // CPROVER_JAVA_BYTECODE_SELECT_POINTER_TYPE_H

0 commit comments

Comments
 (0)