@@ -14,11 +14,46 @@ Author: Chris Smowton, chris.smowton@diffblue.com
1414#include < util/invariant.h>
1515#include < util/suffix.h>
1616
17+ // / Check if we may be in a function that loops over the cases of an
18+ // / enumeration (note we return a candidate function that matches a pattern;
19+ // / our caller must verify it really belongs to an enumeration).
20+ // / At the moment we know of two cases that definitely do so:
21+ // / * An enumeration type's static initialiser
22+ // / * The array[reference].clone() method when called from an enumeration type's
23+ // / 'values()' method
24+ // / \param context: the current call stack
25+ // / \return the name of an enclosing function that may be defined on the
26+ // / relevant enum type, or an empty string if we don't find one.
27+ static irep_idt
28+ find_enum_function_on_stack (const goto_symex_statet::call_stackt &context)
29+ {
30+ static irep_idt reference_array_clone_id =
31+ " java::array[reference].clone:()Ljava/lang/Object;" ;
32+
33+ PRECONDITION (!context.empty ());
34+ const irep_idt ¤t_function = context.back ().function_identifier ;
35+
36+ if (context.size () >= 2 && current_function == reference_array_clone_id)
37+ {
38+ const irep_idt &clone_caller =
39+ context.at (context.size () - 2 ).function_identifier ;
40+ if (id2string (clone_caller).find (" .values:()[L" ) != std::string::npos)
41+ return clone_caller;
42+ else
43+ return irep_idt ();
44+ }
45+ else if (has_suffix (id2string (current_function), " .<clinit>:()V" ))
46+ return current_function;
47+ else
48+ return irep_idt ();
49+ }
50+
1751// / Unwind handler that special-cases the clinit (static initializer) functions
18- // / of enumeration classes. When java_bytecode_convert_classt has annotated them
52+ // / of enumeration classes, and VALUES array cloning in their values() methods.
53+ // / When java_bytecode_convert_classt has annotated them
1954// / with a size of the enumeration type, this forces unwinding of any loop in
2055// / the static initializer to at least that many iterations, with intent to
21- // / permit population of the enumeration's value array.
56+ // / permit population / copying of the enumeration's value array.
2257// / \param function_id: function the loop is in
2358// / \param loop_number: ordinal number of the loop (ignored)
2459// / \param unwind_count: iteration count that is about to begin
@@ -29,17 +64,17 @@ Author: Chris Smowton, chris.smowton@diffblue.com
2964// / unwind_count is <= the enumeration size, or unknown (defer / no decision)
3065// / otherwise.
3166tvt java_enum_static_init_unwind_handler (
32- const irep_idt &function_id ,
67+ const goto_symex_statet::call_stackt &context ,
3368 unsigned loop_number,
3469 unsigned unwind_count,
3570 unsigned &unwind_max,
3671 const symbol_tablet &symbol_table)
3772{
38- const std::string &function_str = id2string (function_id );
39- if (! has_suffix (function_str, " .<clinit>:()V " ))
73+ const irep_idt enum_function_id = find_enum_function_on_stack (context );
74+ if (enum_function_id. empty ( ))
4075 return tvt::unknown ();
4176
42- const symbolt &function_symbol = symbol_table.lookup_ref (function_str );
77+ const symbolt &function_symbol = symbol_table.lookup_ref (enum_function_id );
4378 irep_idt class_id = function_symbol.type .get (ID_C_class);
4479 INVARIANT (
4580 !class_id.empty (), " functions should have their defining class annotated" );
0 commit comments