|
14 | 14 | #include <util/invariant.h>
|
15 | 15 | #include <util/suffix.h>
|
16 | 16 |
|
| 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 | + |
17 | 51 | /// Unwind handler that special-cases the clinit (static initializer) functions
|
18 | 52 | /// of enumeration classes. When java_bytecode_convert_classt has annotated them
|
19 | 53 | /// with a size of the enumeration type, this forces unwinding of any loop in
|
|
29 | 63 | /// unwind_count is <= the enumeration size, or unknown (defer / no decision)
|
30 | 64 | /// otherwise.
|
31 | 65 | tvt java_enum_static_init_unwind_handler(
|
32 |
| - const irep_idt &function_id, |
| 66 | + const goto_symex_statet::call_stackt &context, |
33 | 67 | unsigned loop_number,
|
34 | 68 | unsigned unwind_count,
|
35 | 69 | unsigned &unwind_max,
|
36 | 70 | const symbol_tablet &symbol_table)
|
37 | 71 | {
|
38 |
| - const std::string &function_str = id2string(function_id); |
39 |
| - if(!has_suffix(function_str, ".<clinit>:()V")) |
| 72 | + const irep_idt enum_function_id = find_enum_function_on_stack(context); |
| 73 | + if(enum_function_id.empty()) |
40 | 74 | return tvt::unknown();
|
41 | 75 |
|
42 |
| - const symbolt &function_symbol = symbol_table.lookup_ref(function_str); |
| 76 | + const symbolt &function_symbol = symbol_table.lookup_ref(enum_function_id); |
43 | 77 | irep_idt class_id = function_symbol.type.get(ID_C_class);
|
44 | 78 | INVARIANT(
|
45 | 79 | !class_id.empty(), "functions should have their defining class annotated");
|
|
0 commit comments