1313
1414#include < goto-programs/class_hierarchy.h>
1515#include < goto-programs/class_identifier.h>
16+ #include < goto-programs/goto_convert.h>
1617
1718#include < util/fresh_symbol.h>
1819#include < java_bytecode/java_types.h>
2223class remove_instanceoft
2324{
2425public:
25- explicit remove_instanceoft (symbol_table_baset &symbol_table)
26- : symbol_table(symbol_table), ns(symbol_table)
26+ remove_instanceoft (
27+ symbol_table_baset &symbol_table, message_handlert &message_handler)
28+ : symbol_table(symbol_table)
29+ , ns(symbol_table)
30+ , message_handler(message_handler)
2731 {
2832 class_hierarchy (symbol_table);
2933 }
@@ -38,8 +42,9 @@ class remove_instanceoft
3842 symbol_table_baset &symbol_table;
3943 namespacet ns;
4044 class_hierarchyt class_hierarchy;
45+ message_handlert &message_handler;
4146
42- std:: size_t lower_instanceof (
47+ bool lower_instanceof (
4348 exprt &, goto_programt &, goto_programt::targett);
4449};
4550
@@ -49,18 +54,18 @@ class remove_instanceoft
4954// / \param expr: Expression to lower (the code or the guard of an instruction)
5055// / \param goto_program: program the expression belongs to
5156// / \param this_inst: instruction the expression is found at
52- // / \return number of instanceof expressions that have been replaced
53- std:: size_t remove_instanceoft::lower_instanceof (
57+ // / \return true if any instanceof instructionw was replaced
58+ bool remove_instanceoft::lower_instanceof (
5459 exprt &expr,
5560 goto_programt &goto_program,
5661 goto_programt::targett this_inst)
5762{
5863 if (expr.id ()!=ID_java_instanceof)
5964 {
60- std:: size_t replacements= 0 ;
65+ bool changed = false ;
6166 Forall_operands (it, expr)
62- replacements+= lower_instanceof (*it, goto_program, this_inst);
63- return replacements ;
67+ changed |= lower_instanceof (*it, goto_program, this_inst);
68+ return changed ;
6469 }
6570
6671 INVARIANT (
@@ -94,46 +99,91 @@ std::size_t remove_instanceoft::lower_instanceof(
9499 return a.compare (b) < 0 ;
95100 });
96101
97- // Insert an instruction before the new check that assigns the clsid we're
98- // checking for to a temporary, as GOTO program if-expressions should
99- // not contain derefs.
100- // We actually insert the assignment instruction after the existing one.
101- // This will briefly be ill-formed (use before def of instanceof_tmp) but the
102- // two will subsequently switch places. This makes sure that the inserted
103- // assignement doesn't end up before any labels pointing at this instruction.
102+ // Make temporaries to store the class identifier (avoids repeated derefs) and
103+ // the instanceof result:
104+
104105 symbol_typet jlo=to_symbol_type (java_lang_object_type ().subtype ());
105- exprt object_clsid= get_class_identifier_field (check_ptr, jlo, ns);
106+ exprt object_clsid = get_class_identifier_field (check_ptr, jlo, ns);
106107
107- symbolt &newsym = get_fresh_aux_symbol (
108+ symbolt &clsid_tmp_sym = get_fresh_aux_symbol (
108109 object_clsid.type (),
109110 id2string (this_inst->function ),
110- " instanceof_tmp" ,
111+ " class_identifier_tmp" ,
112+ source_locationt (),
113+ ID_java,
114+ symbol_table);
115+
116+ symbolt &instanceof_result_sym = get_fresh_aux_symbol (
117+ bool_typet (),
118+ id2string (this_inst->function ),
119+ " instanceof_result_tmp" ,
111120 source_locationt (),
112121 ID_java,
113122 symbol_table);
114123
115- auto newinst=goto_program.insert_after (this_inst);
116- newinst->make_assignment ();
117- newinst->code =code_assignt (newsym.symbol_expr (), object_clsid);
118- newinst->source_location =this_inst->source_location ;
119- newinst->function =this_inst->function ;
124+ // Create
125+ // if(expr == null)
126+ // instanceof_result = false;
127+ // else
128+ // string clsid = expr->@class_identifier
129+ // instanceof_result = clsid == "A" || clsid == "B" || ...
120130
121- // Replace the instanceof construct with a conjunction of non-null and the
122- // disjunction of all possible object types. According to the Java
123- // specification, null instanceof T is false for all possible values of T.
131+ // According to the Java specification, null instanceof T is false for all
132+ // possible values of T.
124133 // (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2)
125- notequal_exprt non_null_expr (
126- check_ptr, null_pointer_exprt (to_pointer_type (check_ptr.type ())));
134+
135+ code_ifthenelset is_null_branch;
136+ is_null_branch.cond () =
137+ equal_exprt (
138+ check_ptr, null_pointer_exprt (to_pointer_type (check_ptr.type ())));
139+ is_null_branch.then_case () =
140+ code_assignt (instanceof_result_sym.symbol_expr (), false_exprt ());
141+
142+ code_blockt else_block;
143+ else_block.add (code_declt (clsid_tmp_sym.symbol_expr ()));
144+ else_block.add (code_assignt (clsid_tmp_sym.symbol_expr (), object_clsid));
145+
127146 exprt::operandst or_ops;
128147 for (const auto &clsname : children)
129148 {
130149 constant_exprt clsexpr (clsname, string_typet ());
131- equal_exprt test (newsym .symbol_expr (), clsexpr);
150+ equal_exprt test (clsid_tmp_sym .symbol_expr (), clsexpr);
132151 or_ops.push_back (test);
133152 }
134- expr = and_exprt (non_null_expr, disjunction (or_ops));
153+ else_block.add (
154+ code_assignt (instanceof_result_sym.symbol_expr (), disjunction (or_ops)));
155+
156+ is_null_branch.else_case () = std::move (else_block);
157+
158+ // Replace the instanceof construct with instanceof_result:
159+ expr = instanceof_result_sym.symbol_expr ();
135160
136- return 1 ;
161+ // Insert the new test block before it:
162+ goto_programt new_check_program;
163+ goto_convert (
164+ is_null_branch,
165+ symbol_table,
166+ new_check_program,
167+ message_handler,
168+ ID_java);
169+
170+ goto_program.destructive_insert (this_inst, new_check_program);
171+
172+ return true ;
173+ }
174+
175+ static bool contains_instanceof (const exprt &e)
176+ {
177+ if (e.id () == ID_java_instanceof)
178+ return true ;
179+
180+ for (const exprt &subexpr : e.operands ())
181+ {
182+ if (contains_instanceof (subexpr))
183+ return true ;
184+ }
185+
186+ return false ;
137187}
138188
139189// / Replaces expressions like e instanceof A with e.\@class_identifier == "A"
@@ -146,15 +196,20 @@ bool remove_instanceoft::lower_instanceof(
146196 goto_programt &goto_program,
147197 goto_programt::targett target)
148198{
149- std::size_t replacements=
150- lower_instanceof (target->code , goto_program, target)+
151- lower_instanceof (target->guard , goto_program, target);
199+ if (target->is_target () &&
200+ (contains_instanceof (target->code ) || contains_instanceof (target->guard )))
201+ {
202+ // If this is a branch target, add a skip beforehand so we can splice new
203+ // GOTO programs before the target instruction without inserting into the
204+ // wrong basic block.
205+ goto_program.insert_before_swap (target);
206+ target->make_skip ();
207+ // Actually alter the now-moved instruction:
208+ ++target;
209+ }
152210
153- if (replacements==0 )
154- return false ;
155- // Swap the original instruction with the last assignment added after it
156- target->swap (*std::next (target, replacements));
157- return true ;
211+ return lower_instanceof (target->code , goto_program, target) |
212+ lower_instanceof (target->guard , goto_program, target);
158213}
159214
160215// / Replace every instanceof in the passed function body with an explicit
@@ -185,12 +240,14 @@ bool remove_instanceoft::lower_instanceof(goto_programt &goto_program)
185240// / \param target: The instruction to work on.
186241// / \param goto_program: The function body containing the instruction.
187242// / \param symbol_table: The symbol table to add symbols to.
243+ // / \param message_handler: logging output
188244void remove_instanceof (
189245 goto_programt::targett target,
190246 goto_programt &goto_program,
191- symbol_table_baset &symbol_table)
247+ symbol_table_baset &symbol_table,
248+ message_handlert &message_handler)
192249{
193- remove_instanceoft rem (symbol_table);
250+ remove_instanceoft rem (symbol_table, message_handler );
194251 rem.lower_instanceof (goto_program, target);
195252}
196253
@@ -199,11 +256,13 @@ void remove_instanceof(
199256// / \remarks Extra auxiliary variables may be introduced into symbol_table.
200257// / \param function: The function to work on.
201258// / \param symbol_table: The symbol table to add symbols to.
259+ // / \param message_handler: logging output
202260void remove_instanceof (
203261 goto_functionst::goto_functiont &function,
204- symbol_table_baset &symbol_table)
262+ symbol_table_baset &symbol_table,
263+ message_handlert &message_handler)
205264{
206- remove_instanceoft rem (symbol_table);
265+ remove_instanceoft rem (symbol_table, message_handler );
207266 rem.lower_instanceof (function.body );
208267}
209268
@@ -212,11 +271,13 @@ void remove_instanceof(
212271// / \remarks Extra auxiliary variables may be introduced into symbol_table.
213272// / \param goto_functions: The functions to work on.
214273// / \param symbol_table: The symbol table to add symbols to.
274+ // / \param message_handler: logging output
215275void remove_instanceof (
216276 goto_functionst &goto_functions,
217- symbol_table_baset &symbol_table)
277+ symbol_table_baset &symbol_table,
278+ message_handlert &message_handler)
218279{
219- remove_instanceoft rem (symbol_table);
280+ remove_instanceoft rem (symbol_table, message_handler );
220281 bool changed=false ;
221282 for (auto &f : goto_functions.function_map )
222283 changed=rem.lower_instanceof (f.second .body ) || changed;
@@ -228,8 +289,12 @@ void remove_instanceof(
228289// / class-identifier test.
229290// / \remarks Extra auxiliary variables may be introduced into symbol_table.
230291// / \param goto_model: The functions to work on and the symbol table to add
292+ // / \param message_handler: logging output
231293// / symbols to.
232- void remove_instanceof (goto_modelt &goto_model)
294+ void remove_instanceof (
295+ goto_modelt &goto_model,
296+ message_handlert &message_handler)
233297{
234- remove_instanceof (goto_model.goto_functions , goto_model.symbol_table );
298+ remove_instanceof (
299+ goto_model.goto_functions , goto_model.symbol_table , message_handler);
235300}
0 commit comments