Skip to content

Commit d735cc5

Browse files
committed
Added support for concretising a generic and adding it into the symbol
table.
1 parent 808a6ad commit d735cc5

29 files changed

+462
-109
lines changed
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
public class generics {
2+
3+
class element<E> {
4+
E elem;
5+
}
6+
7+
class bound_element<NUM extends java.lang.Number> {
8+
NUM elem;
9+
NUM f() {
10+
return elem;
11+
}
12+
void g(NUM e) {
13+
elem=e;
14+
}
15+
}
16+
17+
bound_element<Integer> belem;
18+
19+
Integer f(int n) {
20+
21+
element<Integer> e=new element<>();
22+
e.elem=n;
23+
bound_element<Integer> be=new bound_element<>();
24+
belem=new bound_element<>();
25+
be.elem=new Integer(n+1);
26+
if(n>0)
27+
return e.elem;
28+
else
29+
return be.elem;
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
generics.class
3+
--show-symbol-table
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^Type........: struct generics\$bound_element\<java::java.lang.Integer\> \{
7+
__CPROVER_string \@class_identifier; boolean \@lock; struct java.lang.Object \@java.lang.Object; struct java.lang.Integer \*elem; struct generics \*this\$0; \}$
8+
--
+119-40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*******************************************************************\
22
3-
Module: MODULE NAME
3+
Module: Generate Java Generic Type - Instantiate a generic class with
4+
concrete type information.
45
56
Author: DiffBlue Limited. All rights reserved.
67
@@ -10,18 +11,21 @@
1011
#include <java_bytecode/java_types.h>
1112
#include <java_bytecode/java_utils.h>
1213

13-
#include <iostream>
14-
#include <sstream>
1514

1615
generate_java_generic_typet::generate_java_generic_typet(
17-
symbol_tablet &symbol_table,
1816
message_handlert &message_handler):
19-
symbol_table(symbol_table),
2017
message_handler(message_handler)
2118
{}
2219

20+
/// Generate a concrete instantiation of a generic type.
21+
/// \param existing_generic_type The type to be concretised
22+
/// \param symbol_table The symbol table that the concrete type will be
23+
/// inserted into.
24+
/// \return The symbol as it was retrieved from the symbol table after
25+
/// it has been inserted into.
2326
symbolt generate_java_generic_typet::operator()(
24-
const java_type_with_generic_typet &existing_generic_type)
27+
const java_generic_typet &existing_generic_type,
28+
symbol_tablet &symbol_table) const
2529
{
2630
namespacet ns(symbol_table);
2731

@@ -30,58 +34,90 @@ symbolt generate_java_generic_typet::operator()(
3034
INVARIANT(
3135
pointer_subtype.id()==ID_struct, "Only pointers to classes in java");
3236

33-
const java_class_typet &java_class=to_java_class_type(pointer_subtype);
34-
35-
java_class_typet replacement_type=java_class;
36-
replacement_type.components().clear();
37-
38-
const irep_idt new_tag=build_generic_tag(existing_generic_type, java_class);
39-
replacement_type.set_tag(new_tag);
40-
41-
for(const struct_union_typet::componentt &component_type :
42-
java_class.components())
43-
{
44-
if(!is_java_generic_type(component_type.type()))
37+
const java_class_typet &replacement_type=
38+
to_java_class_type(pointer_subtype);
39+
const irep_idt new_tag=build_generic_tag(
40+
existing_generic_type, replacement_type);
41+
struct_union_typet::componentst replacement_components=
42+
replacement_type.components();
43+
44+
// Small auxiliary function, to perform the inplace
45+
// modification of the generic fields.
46+
auto replace_type_for_generic_field=
47+
[&](struct_union_typet::componentt &component)
4548
{
46-
replacement_type.components().push_back(component_type);
47-
continue;
48-
}
49+
if(is_java_generic_parameter(component.type()))
50+
{
51+
auto replacement_type_param=
52+
to_java_generics_class_type(replacement_type);
53+
54+
auto component_identifier=
55+
to_java_generic_parameter(component.type()).type_variable()
56+
.get_identifier();
57+
58+
optionalt<size_t> results=java_generics_get_index_for_subtype(
59+
replacement_type_param, component_identifier);
60+
61+
INVARIANT(
62+
results.has_value(),
63+
"generic component type not found");
64+
65+
if(results)
66+
{
67+
component.type()=
68+
existing_generic_type.generic_type_variables()[*results];
69+
}
70+
}
71+
return component;
72+
};
73+
74+
std::size_t pre_modification_size=to_java_class_type(
75+
ns.follow(existing_generic_type.subtype())).components().size();
76+
77+
std::for_each(
78+
replacement_components.begin(),
79+
replacement_components.end(),
80+
replace_type_for_generic_field);
81+
82+
std::size_t after_modification_size=
83+
replacement_type.components().size();
4984

50-
INVARIANT(
51-
existing_generic_type.type_parameters.size()==1,
52-
"Must have a type parameter");
53-
54-
struct_union_typet::componentt replacement_comp=component_type;
55-
replacement_comp.type()=existing_generic_type.type_parameters[0];
56-
57-
replacement_type.components().push_back(replacement_comp);
58-
59-
}
6085
INVARIANT(
61-
replacement_type.components().size()==java_class.components().size(),
86+
pre_modification_size==after_modification_size,
6287
"All components in the original class should be in the new class");
6388

64-
generate_class_stub(new_tag, symbol_table, message_handler);
65-
INVARIANT(symbol_table.has_symbol("java::"+id2string(new_tag)), "New class not created");
66-
return symbol_table.lookup("java::"+id2string(new_tag));
89+
const auto expected_symbol="java::"+id2string(new_tag);
90+
91+
generate_class_stub(
92+
new_tag,
93+
symbol_table,
94+
message_handler,
95+
replacement_components);
96+
auto symbol=symbol_table.lookup(expected_symbol);
97+
INVARIANT(symbol, "New class not created");
98+
return *symbol;
6799
}
68100

101+
/// Build a unique tag for the generic to be instantiated.
102+
/// \param existing_generic_type The type we want to concretise
103+
/// \param original_class
104+
/// \return A tag for the new generic we want a unique tag for.
69105
irep_idt generate_java_generic_typet::build_generic_tag(
70-
const java_type_with_generic_typet &existing_generic_type,
71-
const java_class_typet &original_class)
106+
const java_generic_typet &existing_generic_type,
107+
const java_class_typet &original_class) const
72108
{
73109
std::ostringstream new_tag_buffer;
74110
new_tag_buffer << original_class.get_tag();
75111
new_tag_buffer << "<";
76112
bool first=true;
77-
for(const typet &param : existing_generic_type.type_parameters)
113+
for(const typet &param : existing_generic_type.generic_type_variables())
78114
{
79115
if(!first)
80-
new_tag_buffer << ", ";
116+
new_tag_buffer << ",";
81117
first=false;
82118

83119
INVARIANT(
84-
is_java_inst_generic_type(param),
120+
is_java_generic_inst_parameter(param),
85121
"Only create full concretized generic types");
86122
new_tag_buffer << param.subtype().get(ID_identifier);
87123
}
@@ -90,3 +126,46 @@ irep_idt generate_java_generic_typet::build_generic_tag(
90126

91127
return new_tag_buffer.str();
92128
}
129+
130+
131+
/// Activate the generic instantiation code.
132+
/// \param message_handler
133+
/// \param symbol_table The symbol table so far.
134+
void
135+
instantiate_generics(
136+
message_handlert &message_handler,
137+
symbol_tablet &symbol_table)
138+
{
139+
generate_java_generic_typet instantiate_generic_type(message_handler);
140+
// check out the symbols in the symbol table at this point to see if we
141+
// have a a generic type in.
142+
for(const auto &symbol : symbol_table.symbols)
143+
{
144+
if(symbol.second.type.id()==ID_struct)
145+
{
146+
auto symbol_struct=to_struct_type(symbol.second.type);
147+
auto &components=symbol_struct.components();
148+
149+
for(const auto &component : components)
150+
{
151+
if(is_java_generic_type(component.type()))
152+
{
153+
const auto &type_vars=to_java_generic_type(component.type()).
154+
generic_type_variables();
155+
156+
// Before we can instantiate a generic component, we need
157+
// its type variables to be instantiated parameters
158+
if(all_of(type_vars.cbegin(), type_vars.cend(),
159+
[](const typet &type)
160+
{
161+
return is_java_generic_inst_parameter(type);
162+
}))
163+
{
164+
instantiate_generic_type(
165+
to_java_generic_type(component.type()), symbol_table);
166+
}
167+
}
168+
}
169+
}
170+
}
171+
}
+13-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
/*******************************************************************\
22
3-
Module: MODULE NAME
3+
Module: Generate Java Generic Type - Instantiate a generic class with
4+
concrete type information.
45
56
Author: DiffBlue Limited. All rights reserved.
67
78
\*******************************************************************/
8-
#ifndef GENERATE_JAVA_GENERIC_TYPE_H
9-
#define GENERATE_JAVA_GENERIC_TYPE_H
9+
#ifndef CPROVER_JAVA_BYTECODE_GENERATE_JAVA_GENERIC_TYPE_H
10+
#define CPROVER_JAVA_BYTECODE_GENERATE_JAVA_GENERIC_TYPE_H
1011

1112
#include <util/message.h>
1213
#include <util/symbol_table.h>
@@ -17,20 +18,21 @@ class generate_java_generic_typet
1718
{
1819
public:
1920
generate_java_generic_typet(
20-
symbol_tablet &symbol_table,
2121
message_handlert &message_handler);
2222

2323
symbolt operator()(
24-
const java_type_with_generic_typet &existing_generic_type);
24+
const java_generic_typet &existing_generic_type,
25+
symbol_tablet &symbol_table) const;
2526
private:
2627
irep_idt build_generic_tag(
27-
const java_type_with_generic_typet &existing_generic_type,
28-
const java_class_typet &original_class);
29-
30-
symbol_tablet &symbol_table;
28+
const java_generic_typet &existing_generic_type,
29+
const java_class_typet &original_class) const;
3130

3231
message_handlert &message_handler;
33-
3432
};
3533

36-
#endif // GENERATE_JAVA_GENERIC_TYPE_H
34+
void instantiate_generics(
35+
message_handlert &message_handler,
36+
symbol_tablet &symbol_table);
37+
38+
#endif // CPROVER_JAVA_BYTECODE_GENERATE_JAVA_GENERIC_TYPE_H

src/java_bytecode/java_bytecode_convert_class.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ class java_bytecode_convert_classt:public messaget
6363
generate_class_stub(
6464
parse_tree.parsed_class.name,
6565
symbol_table,
66-
get_message_handler());
66+
get_message_handler(),
67+
struct_union_typet::componentst{});
6768
}
6869

6970
typedef java_bytecode_parse_treet::classt classt;

src/java_bytecode/java_bytecode_instrument.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ codet java_bytecode_instrumentt::throw_exception(
100100
generate_class_stub(
101101
exc_name,
102102
symbol_table,
103-
get_message_handler());
103+
get_message_handler(),
104+
struct_union_typet::componentst{});
104105
}
105106

106107
pointer_typet exc_ptr_type=

src/java_bytecode/java_bytecode_language.cpp

+15-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Author: Daniel Kroening, [email protected]
3030
#include "java_class_loader.h"
3131
#include "java_utils.h"
3232
#include <java_bytecode/ci_lazy_methods.h>
33+
#include <java_bytecode/generate_java_generic_type.h>
3334

3435
#include "expr2java.h"
3536

@@ -238,11 +239,21 @@ bool java_bytecode_languaget::typecheck(
238239
get_message_handler());
239240

240241
// now typecheck all
241-
if(java_bytecode_typecheck(
242-
symbol_table, get_message_handler(), string_refinement_enabled))
243-
return true;
242+
bool res=java_bytecode_typecheck(
243+
symbol_table, get_message_handler(), string_refinement_enabled);
244+
// NOTE (FOTIS): There is some unintuitive logic here, where
245+
// java_bytecode_check will return TRUE if typechecking failed, and FALSE
246+
// if everything went well...
247+
if(res)
248+
{
249+
// there is no point in continuing to concretise
250+
// the generic types if typechecking failed.
251+
return res;
252+
}
244253

245-
return false;
254+
instantiate_generics(get_message_handler(), symbol_table);
255+
256+
return res;
246257
}
247258

248259
bool java_bytecode_languaget::generate_support_functions(

src/java_bytecode/java_types.h

+28
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Author: Daniel Kroening, [email protected]
1111
#define CPROVER_JAVA_BYTECODE_JAVA_TYPES_H
1212

1313
#include <util/invariant.h>
14+
#include <algorithm>
15+
1416
#include <util/type.h>
1517
#include <util/std_types.h>
1618
#include <util/c_types.h>
@@ -379,4 +381,30 @@ inline typet java_type_from_string_with_exception(
379381
}
380382
}
381383

384+
/// Get the index in the subtypes array for a given component.
385+
/// \param t The type we search for the subtypes in.
386+
/// \param identifier The string identifier of the type of the component.
387+
/// \return Optional with the size if the identifier was found.
388+
inline const optionalt<size_t> java_generics_get_index_for_subtype(
389+
const java_generics_class_typet &t,
390+
const irep_idt &identifier)
391+
{
392+
const std::vector<java_generic_parametert> &gen_types=t.generic_types();
393+
394+
const auto iter = std::find_if(
395+
gen_types.cbegin(),
396+
gen_types.cend(),
397+
[&identifier](const java_generic_parametert &ref)
398+
{
399+
return ref.type_variable().get_identifier()==identifier;
400+
});
401+
402+
if(iter==gen_types.cend())
403+
{
404+
return {};
405+
}
406+
407+
return std::distance(gen_types.cbegin(), iter);
408+
}
409+
382410
#endif // CPROVER_JAVA_BYTECODE_JAVA_TYPES_H

0 commit comments

Comments
 (0)