Skip to content

Commit 31004f5

Browse files
author
Matthias Güdemann
committed
Search through stack for instantiation
1 parent 3264023 commit 31004f5

File tree

2 files changed

+117
-8
lines changed

2 files changed

+117
-8
lines changed

jbmc/src/java_bytecode/select_pointer_type.cpp

Lines changed: 108 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ pointer_typet select_pointer_typet::convert_pointer_type(
3333
if(!generic_parameter_specialization_map.empty())
3434
{
3535
generic_parameter_recursion_trackingt visited;
36-
return specialize_generics(
36+
auto type = specialize_generics(
3737
pointer_type, generic_parameter_specialization_map, visited);
38+
INVARIANT(visited.empty(), "recursion stack must be empty here");
39+
return type;
3840
}
3941
else
4042
{
@@ -86,18 +88,31 @@ pointer_typet select_pointer_typet::specialize_generics(
8688
// information from further recursion, only cause a segmentation fault.
8789
if(visited_nodes.find(parameter_name) != visited_nodes.end())
8890
{
91+
optionalt<pointer_typet> result = get_instantiated_type(
92+
parameter_name, generic_parameter_specialization_map);
93+
if(result.has_value())
94+
{
95+
return result.value();
96+
}
8997
throw "no infinite recursion";
9098
}
9199

92-
visited_nodes.insert(parameter_name);
93-
94100
// generic parameters can be adopted from outer classes or superclasses so
95101
// we may need to search for the concrete type recursively
96-
return is_java_generic_parameter(type)
97-
? specialize_generics(
98-
to_java_generic_parameter(type),
99-
generic_parameter_specialization_map, visited_nodes)
100-
: type;
102+
if(is_java_generic_parameter(type))
103+
{
104+
visited_nodes.insert(parameter_name);
105+
auto returned_type = specialize_generics(
106+
to_java_generic_parameter(type),
107+
generic_parameter_specialization_map,
108+
visited_nodes);
109+
visited_nodes.erase(parameter_name);
110+
return returned_type;
111+
}
112+
else
113+
{
114+
return type;
115+
}
101116
}
102117
else if(pointer_type.subtype().id() == ID_symbol)
103118
{
@@ -120,3 +135,88 @@ pointer_typet select_pointer_typet::specialize_generics(
120135
}
121136
return pointer_type;
122137
}
138+
139+
/// Return the first concrete type instantiation if any such exists.
140+
/// \param parameter_name The name of the generic parameter type we want to have
141+
/// instantiated
142+
/// \param generic_specialization_map Map of type names to specialization stack
143+
/// \param depth start depth for instantiation search
144+
/// \return the first instantiated type for the generic type or nothing if no
145+
/// such instantiation exists.
146+
optionalt<pointer_typet> select_pointer_typet::get_instantiated_type(
147+
const irep_idt &parameter_name,
148+
const generic_parameter_specialization_mapt
149+
&generic_parameter_specialization_map) const
150+
{
151+
generic_parameter_recursion_trackingt visited;
152+
const auto retval = get_instantiated_type(
153+
parameter_name, generic_parameter_specialization_map, visited, 0);
154+
INVARIANT(visited.empty(), "recursion set must be empty here");
155+
return retval;
156+
}
157+
158+
/// See above, the additional parameter just tracks the recursion to prevent
159+
/// visiting the same depth again.
160+
/// \param visited tracks the visited parameter names
161+
optionalt<pointer_typet> select_pointer_typet::get_instantiated_type(
162+
const irep_idt &parameter_name,
163+
const generic_parameter_specialization_mapt
164+
&generic_parameter_specialization_map,
165+
generic_parameter_recursion_trackingt &visited,
166+
const size_t depth) const
167+
{
168+
// Get the pointed to instantiation type at the desired stack depth.
169+
// - f this type is not a generic type, it is returned as a valid
170+
// instantiation
171+
// - if another recursion at this depth level is found, the search depth is
172+
// increased
173+
// - if nothing can be found an empty optional is returned
174+
175+
if(
176+
generic_parameter_specialization_map.find(parameter_name) !=
177+
generic_parameter_specialization_map.end())
178+
{
179+
const auto &replacements =
180+
generic_parameter_specialization_map.find(parameter_name)->second;
181+
182+
// max depth reached and nothing found
183+
if(replacements.size() <= depth)
184+
return {};
185+
186+
// Check if there is a recursion loop, if yes increase search depth
187+
if(visited.find(parameter_name) != visited.end())
188+
{
189+
visited.clear();
190+
return get_instantiated_type(
191+
parameter_name, generic_parameter_specialization_map, visited, depth+1);
192+
}
193+
else
194+
{
195+
const size_t index = (replacements.size() - depth) - 1;
196+
const auto &type = replacements[index];
197+
{
198+
if(!is_java_generic_parameter(type))
199+
{
200+
return type;
201+
}
202+
else
203+
{
204+
visited.insert(parameter_name);
205+
const auto &gen_type = to_java_generic_parameter(type).type_variable();
206+
const auto val = get_instantiated_type(
207+
gen_type.get_identifier(),
208+
generic_parameter_specialization_map,
209+
visited,
210+
depth);
211+
visited.erase(parameter_name);
212+
return val;
213+
}
214+
}
215+
}
216+
}
217+
// parameter_name not found in map
218+
else
219+
{
220+
UNREACHABLE;
221+
}
222+
}

jbmc/src/java_bytecode/select_pointer_type.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ class namespacet;
2525

2626
class select_pointer_typet
2727
{
28+
optionalt<pointer_typet> get_instantiated_type(
29+
const irep_idt &,
30+
const generic_parameter_specialization_mapt &,
31+
generic_parameter_recursion_trackingt &,
32+
const size_t) const;
33+
optionalt<pointer_typet> get_instantiated_type(
34+
const irep_idt &parameter_name,
35+
const generic_parameter_specialization_mapt &) const;
36+
2837
public:
2938
virtual ~select_pointer_typet() = default;
3039
virtual pointer_typet convert_pointer_type(

0 commit comments

Comments
 (0)