@@ -106,6 +106,125 @@ static constant_exprt constant_bool(bool val)
106106 return from_integer (val ? 1 : 0 , java_boolean_type ());
107107}
108108
109+ static std::unordered_set<irep_idt> init_symbol (
110+ const symbolt &sym,
111+ code_blockt &code_block,
112+ symbol_table_baset &symbol_table,
113+ const source_locationt &source_location,
114+ bool assume_init_pointers_not_null,
115+ const java_object_factory_parameterst &object_factory_parameters,
116+ const select_pointer_typet &pointer_type_selector,
117+ bool string_refinement_enabled,
118+ message_handlert &message_handler)
119+ {
120+ std::unordered_set<irep_idt> additional_symbols;
121+
122+ if (
123+ const symbolt *class_literal_init_method =
124+ get_class_literal_initializer (sym, symbol_table))
125+ {
126+ const std::string &name_str = id2string (sym.name );
127+ irep_idt class_name =
128+ name_str.substr (0 , name_str.size () - strlen (JAVA_CLASS_MODEL_SUFFIX));
129+ const symbolt &class_symbol = symbol_table.lookup_ref (class_name);
130+
131+ bool class_is_array = is_java_array_tag (sym.name );
132+
133+ journalling_symbol_tablet journalling_table =
134+ journalling_symbol_tablet::wrap (symbol_table);
135+
136+ symbol_exprt class_name_literal = get_or_create_string_literal_symbol (
137+ to_class_type (class_symbol.type ).get_tag (),
138+ journalling_table,
139+ string_refinement_enabled);
140+
141+ // If that created any new symbols make sure we initialise those too:
142+ additional_symbols = journalling_table.get_inserted ();
143+
144+ // Call the literal initializer method instead of a nondet initializer:
145+
146+ // For arguments we can't parse yet:
147+ side_effect_expr_nondett nondet_bool (java_boolean_type (), sym.location );
148+
149+ const auto &java_class_type = to_java_class_type (class_symbol.type );
150+
151+ // Argument order is: name, isAnnotation, isArray, isInterface,
152+ // isSynthetic, isLocalClass, isMemberClass, isEnum
153+
154+ code_function_callt initializer_call (
155+ class_literal_init_method->symbol_expr (),
156+ {// this:
157+ address_of_exprt (sym.symbol_expr ()),
158+ // name:
159+ address_of_exprt (class_name_literal),
160+ // isAnnotation:
161+ constant_bool (java_class_type.get_is_annotation ()),
162+ // isArray:
163+ constant_bool (class_is_array),
164+ // isInterface:
165+ constant_bool (java_class_type.get_interface ()),
166+ // isSynthetic:
167+ constant_bool (java_class_type.get_synthetic ()),
168+ // isLocalClass:
169+ nondet_bool,
170+ // isMemberClass:
171+ nondet_bool,
172+ // isEnum:
173+ constant_bool (java_class_type.get_is_enumeration ())});
174+
175+ // First initialize the object as prior to a constructor:
176+ namespacet ns (symbol_table);
177+
178+ auto zero_object = zero_initializer (sym.type , source_locationt (), ns);
179+ if (!zero_object.has_value ())
180+ {
181+ messaget message (message_handler);
182+ message.error () << " failed to zero-initialize " << sym.name
183+ << messaget::eom;
184+ throw 0 ;
185+ }
186+ set_class_identifier (
187+ to_struct_expr (*zero_object), ns, to_struct_tag_type (sym.type ));
188+
189+ code_block.add (
190+ std::move (code_frontend_assignt (sym.symbol_expr (), *zero_object)));
191+
192+ // Then call the init function:
193+ code_block.add (std::move (initializer_call));
194+ }
195+ else if (sym.value .is_nil () && sym.type != java_void_type ())
196+ {
197+ const bool is_class_model = has_suffix (id2string (sym.name ), " @class_model" );
198+ const bool not_allow_null = is_java_string_literal_id (sym.name ) ||
199+ is_non_null_library_global (sym.name ) ||
200+ assume_init_pointers_not_null;
201+
202+ java_object_factory_parameterst parameters = object_factory_parameters;
203+ if (not_allow_null && !is_class_model)
204+ parameters.min_null_tree_depth = 1 ;
205+
206+ gen_nondet_init (
207+ sym.symbol_expr (),
208+ code_block,
209+ symbol_table,
210+ source_location,
211+ false ,
212+ lifetimet::STATIC_GLOBAL,
213+ parameters,
214+ pointer_type_selector,
215+ update_in_placet::NO_UPDATE_IN_PLACE,
216+ message_handler);
217+ }
218+ else if (sym.value .is_not_nil ())
219+ {
220+ code_frontend_assignt assignment (sym.symbol_expr (), sym.value );
221+ assignment.add_source_location () = source_location;
222+ code_block.add (assignment);
223+ }
224+
225+ return additional_symbols;
226+ }
227+
109228void java_static_lifetime_init (
110229 symbol_table_baset &symbol_table,
111230 const source_locationt &source_location,
@@ -142,127 +261,40 @@ void java_static_lifetime_init(
142261 // external. Iterate over a copy of the symtab, as its iterators are
143262 // invalidated by object_factory:
144263
145- std::list<irep_idt> symbol_names;
264+ // sort alphabetically for reproducible results
265+ std::set<std::string> symbol_names;
146266 for (const auto &entry : symbol_table.symbols )
147- symbol_names.push_back (entry.first );
148-
149- // Don't use a for-each loop here because the loop extends the list, and the
150- // for-each loop may only read `.end()` once.
151- for (
152- auto symbol_it = symbol_names.begin ();
153- symbol_it != symbol_names.end ();
154- ++symbol_it)
267+ symbol_names.insert (id2string (entry.first ));
268+
269+ std::set<std::string> additional_symbols;
270+ while (!symbol_names.empty () || !additional_symbols.empty ())
155271 {
156- const auto &symname = *symbol_it;
157- const symbolt &sym = symbol_table.lookup_ref (symname);
158- if (should_init_symbol (sym))
272+ if (!additional_symbols.empty ())
273+ symbol_names.swap (additional_symbols);
274+
275+ for (const auto &symbol_name : symbol_names)
159276 {
160- if (const symbolt *class_literal_init_method =
161- get_class_literal_initializer (sym, symbol_table))
162- {
163- const std::string &name_str = id2string (sym.name );
164- irep_idt class_name =
165- name_str.substr (0 , name_str.size () - strlen (JAVA_CLASS_MODEL_SUFFIX));
166- const symbolt &class_symbol = symbol_table.lookup_ref (class_name);
167-
168- bool class_is_array = is_java_array_tag (sym.name );
169-
170- journalling_symbol_tablet journalling_table =
171- journalling_symbol_tablet::wrap (symbol_table);
172-
173- symbol_exprt class_name_literal = get_or_create_string_literal_symbol (
174- to_class_type (class_symbol.type ).get_tag (),
175- journalling_table,
176- string_refinement_enabled);
177-
178- // If that created any new symbols make sure we initialise those too:
179- const auto &new_symbols = journalling_table.get_inserted ();
180- symbol_names.insert (
181- symbol_names.end (), new_symbols.begin (), new_symbols.end ());
182-
183- // Call the literal initializer method instead of a nondet initializer:
184-
185- // For arguments we can't parse yet:
186- side_effect_expr_nondett nondet_bool (java_boolean_type (), sym.location );
187-
188- const auto &java_class_type = to_java_class_type (class_symbol.type );
189-
190- // Argument order is: name, isAnnotation, isArray, isInterface,
191- // isSynthetic, isLocalClass, isMemberClass, isEnum
192-
193- code_function_callt initializer_call (
194- class_literal_init_method->symbol_expr (),
195- {// this:
196- address_of_exprt (sym.symbol_expr ()),
197- // name:
198- address_of_exprt (class_name_literal),
199- // isAnnotation:
200- constant_bool (java_class_type.get_is_annotation ()),
201- // isArray:
202- constant_bool (class_is_array),
203- // isInterface:
204- constant_bool (java_class_type.get_interface ()),
205- // isSynthetic:
206- constant_bool (java_class_type.get_synthetic ()),
207- // isLocalClass:
208- nondet_bool,
209- // isMemberClass:
210- nondet_bool,
211- // isEnum:
212- constant_bool (java_class_type.get_is_enumeration ())});
213-
214- // First initialize the object as prior to a constructor:
215- namespacet ns (symbol_table);
216-
217- auto zero_object = zero_initializer (sym.type , source_locationt (), ns);
218- if (!zero_object.has_value ())
219- {
220- messaget message (message_handler);
221- message.error () << " failed to zero-initialize " << sym.name
222- << messaget::eom;
223- throw 0 ;
224- }
225- set_class_identifier (
226- to_struct_expr (*zero_object), ns, to_struct_tag_type (sym.type ));
227-
228- code_block.add (
229- std::move (code_frontend_assignt (sym.symbol_expr (), *zero_object)));
230-
231- // Then call the init function:
232- code_block.add (std::move (initializer_call));
233- }
234- else if (sym.value .is_nil () && sym.type != java_void_type ())
277+ const symbolt &sym = symbol_table.lookup_ref (symbol_name);
278+ if (should_init_symbol (sym))
235279 {
236- const bool is_class_model =
237- has_suffix (id2string (sym.name ), " @class_model" );
238- const bool not_allow_null = is_java_string_literal_id (sym.name ) ||
239- is_non_null_library_global (sym.name ) ||
240- assume_init_pointers_not_null;
241-
242- java_object_factory_parameterst parameters = object_factory_parameters;
243- if (not_allow_null && !is_class_model)
244- parameters.min_null_tree_depth = 1 ;
245-
246- gen_nondet_init (
247- sym.symbol_expr (),
280+ auto new_symbols = init_symbol (
281+ sym,
248282 code_block,
249283 symbol_table,
250284 source_location,
251- false ,
252- lifetimet::STATIC_GLOBAL,
253- parameters,
285+ assume_init_pointers_not_null,
286+ object_factory_parameters,
254287 pointer_type_selector,
255- update_in_placet::NO_UPDATE_IN_PLACE ,
288+ string_refinement_enabled ,
256289 message_handler);
257- }
258- else if (sym.value .is_not_nil ())
259- {
260- code_frontend_assignt assignment (sym.symbol_expr (), sym.value );
261- assignment.add_source_location ()=source_location;
262- code_block.add (assignment);
290+ for (const auto &new_symbol_name : new_symbols)
291+ additional_symbols.insert (id2string (new_symbol_name));
263292 }
264293 }
294+
295+ symbol_names.clear ();
265296 }
297+
266298 initialize_symbol.value = std::move (code_block);
267299}
268300
0 commit comments