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>
@@ -39,7 +40,7 @@ class remove_instanceoft
3940 namespacet ns;
4041 class_hierarchyt class_hierarchy;
4142
42- std:: size_t lower_instanceof (
43+ bool lower_instanceof (
4344 exprt &, goto_programt &, goto_programt::targett);
4445};
4546
@@ -49,18 +50,18 @@ class remove_instanceoft
4950// / \param expr: Expression to lower (the code or the guard of an instruction)
5051// / \param goto_program: program the expression belongs to
5152// / \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 (
53+ // / \return true if any instanceof instructionw was replaced
54+ bool remove_instanceoft::lower_instanceof (
5455 exprt &expr,
5556 goto_programt &goto_program,
5657 goto_programt::targett this_inst)
5758{
5859 if (expr.id ()!=ID_java_instanceof)
5960 {
60- std:: size_t replacements= 0 ;
61+ bool changed = false ;
6162 Forall_operands (it, expr)
62- replacements+= lower_instanceof (*it, goto_program, this_inst);
63- return replacements ;
63+ changed |= lower_instanceof (*it, goto_program, this_inst);
64+ return changed ;
6465 }
6566
6667 INVARIANT (
@@ -94,46 +95,93 @@ std::size_t remove_instanceoft::lower_instanceof(
9495 return a.compare (b) < 0 ;
9596 });
9697
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.
98+ // Make temporaries to store the class identifier (avoids repeated derefs) and
99+ // the instanceof result:
100+
104101 symbol_typet jlo=to_symbol_type (java_lang_object_type ().subtype ());
105- exprt object_clsid= get_class_identifier_field (check_ptr, jlo, ns);
102+ exprt object_clsid = get_class_identifier_field (check_ptr, jlo, ns);
106103
107- symbolt &newsym = get_fresh_aux_symbol (
104+ symbolt &clsid_tmp_sym = get_fresh_aux_symbol (
108105 object_clsid.type (),
109106 id2string (this_inst->function ),
110- " instanceof_tmp" ,
107+ " class_identifier_tmp" ,
108+ source_locationt (),
109+ ID_java,
110+ symbol_table);
111+
112+ symbolt &instanceof_result_sym = get_fresh_aux_symbol (
113+ bool_typet (),
114+ id2string (this_inst->function ),
115+ " instanceof_result_tmp" ,
111116 source_locationt (),
112117 ID_java,
113118 symbol_table);
114119
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 ;
120+ // Create
121+ // if(expr == null)
122+ // instanceof_result = false;
123+ // else
124+ // string clsid = expr->@class_identifier
125+ // instanceof_result = clsid == "A" || clsid == "B" || ...
120126
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.
127+ // According to the Java specification, null instanceof T is false for all
128+ // possible values of T.
124129 // (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 ())));
130+
131+ code_ifthenelset is_null_branch;
132+ is_null_branch.cond () =
133+ equal_exprt (
134+ check_ptr, null_pointer_exprt (to_pointer_type (check_ptr.type ())));
135+ is_null_branch.then_case () =
136+ code_assignt (instanceof_result_sym.symbol_expr (), false_exprt ());
137+
138+ code_blockt else_block;
139+ else_block.add (code_declt (clsid_tmp_sym.symbol_expr ()));
140+ else_block.add (code_assignt (clsid_tmp_sym.symbol_expr (), object_clsid));
141+
127142 exprt::operandst or_ops;
128143 for (const auto &clsname : children)
129144 {
130145 constant_exprt clsexpr (clsname, string_typet ());
131- equal_exprt test (newsym .symbol_expr (), clsexpr);
146+ equal_exprt test (clsid_tmp_sym .symbol_expr (), clsexpr);
132147 or_ops.push_back (test);
133148 }
134- expr = and_exprt (non_null_expr, disjunction (or_ops));
149+ else_block.add (
150+ code_assignt (instanceof_result_sym.symbol_expr (), disjunction (or_ops)));
151+
152+ is_null_branch.else_case () = std::move (else_block);
153+
154+ // Replace the instanceof construct with instanceof_result:
155+ expr = instanceof_result_sym.symbol_expr ();
156+
157+ null_message_handlert replaceme;
158+
159+ // Insert the new test block before it:
160+ goto_programt new_check_program;
161+ goto_convert (
162+ is_null_branch,
163+ symbol_table,
164+ new_check_program,
165+ replaceme,
166+ ID_java);
167+
168+ goto_program.destructive_insert (this_inst, new_check_program);
135169
136- return 1 ;
170+ return true ;
171+ }
172+
173+ static bool contains_instanceof (const exprt &e)
174+ {
175+ if (e.id () == ID_java_instanceof)
176+ return true ;
177+
178+ for (const exprt &subexpr : e.operands ())
179+ {
180+ if (contains_instanceof (subexpr))
181+ return true ;
182+ }
183+
184+ return false ;
137185}
138186
139187// / Replaces expressions like e instanceof A with e.\@class_identifier == "A"
@@ -146,15 +194,20 @@ bool remove_instanceoft::lower_instanceof(
146194 goto_programt &goto_program,
147195 goto_programt::targett target)
148196{
149- std::size_t replacements=
150- lower_instanceof (target->code , goto_program, target)+
151- lower_instanceof (target->guard , goto_program, target);
197+ if (target->is_target () &&
198+ (contains_instanceof (target->code ) || contains_instanceof (target->guard )))
199+ {
200+ // If this is a branch target, add a skip beforehand so we can splice new
201+ // GOTO programs before the target instruction without inserting into the
202+ // wrong basic block.
203+ goto_program.insert_before_swap (target);
204+ target->make_skip ();
205+ // Actually alter the now-moved instruction:
206+ ++target;
207+ }
152208
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 ;
209+ return lower_instanceof (target->code , goto_program, target) |
210+ lower_instanceof (target->guard , goto_program, target);
158211}
159212
160213// / Replace every instanceof in the passed function body with an explicit
0 commit comments