13
13
14
14
#include < goto-programs/class_hierarchy.h>
15
15
#include < goto-programs/class_identifier.h>
16
+ #include < goto-programs/goto_convert.h>
16
17
17
18
#include < util/fresh_symbol.h>
18
19
#include < java_bytecode/java_types.h>
@@ -39,7 +40,7 @@ class remove_instanceoft
39
40
namespacet ns;
40
41
class_hierarchyt class_hierarchy;
41
42
42
- std:: size_t lower_instanceof (
43
+ bool lower_instanceof (
43
44
exprt &, goto_programt &, goto_programt::targett);
44
45
};
45
46
@@ -49,18 +50,18 @@ class remove_instanceoft
49
50
// / \param expr: Expression to lower (the code or the guard of an instruction)
50
51
// / \param goto_program: program the expression belongs to
51
52
// / \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 (
54
55
exprt &expr,
55
56
goto_programt &goto_program,
56
57
goto_programt::targett this_inst)
57
58
{
58
59
if (expr.id ()!=ID_java_instanceof)
59
60
{
60
- std:: size_t replacements= 0 ;
61
+ bool changed = false ;
61
62
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 ;
64
65
}
65
66
66
67
INVARIANT (
@@ -94,46 +95,99 @@ std::size_t remove_instanceoft::lower_instanceof(
94
95
return a.compare (b) < 0 ;
95
96
});
96
97
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
+
104
101
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);
106
103
107
- symbolt &newsym = get_fresh_aux_symbol (
104
+ symbolt &clsid_tmp_sym = get_fresh_aux_symbol (
108
105
object_clsid.type (),
109
106
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" ,
111
116
source_locationt (),
112
117
ID_java,
113
118
symbol_table);
114
119
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" || ...
120
126
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.
124
129
// (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
+
127
142
exprt::operandst or_ops;
128
143
for (const auto &clsname : children)
129
144
{
130
145
constant_exprt clsexpr (clsname, string_typet ());
131
- equal_exprt test (newsym .symbol_expr (), clsexpr);
146
+ equal_exprt test (clsid_tmp_sym .symbol_expr (), clsexpr);
132
147
or_ops.push_back (test);
133
148
}
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
+ std::ostringstream convert_output;
158
+ stream_message_handlert convert_message_handler (convert_output);
159
+
160
+ // Insert the new test block before it:
161
+ goto_programt new_check_program;
162
+ goto_convert (
163
+ is_null_branch,
164
+ symbol_table,
165
+ new_check_program,
166
+ convert_message_handler,
167
+ ID_java);
168
+
169
+ INVARIANT (
170
+ convert_output.str ().empty (),
171
+ " remove_instanceof generated test should be goto-converted without error, "
172
+ " but goto_convert reported: " + convert_output.str ());
135
173
136
- return 1 ;
174
+ goto_program.destructive_insert (this_inst, new_check_program);
175
+
176
+ return true ;
177
+ }
178
+
179
+ static bool contains_instanceof (const exprt &e)
180
+ {
181
+ if (e.id () == ID_java_instanceof)
182
+ return true ;
183
+
184
+ for (const exprt &subexpr : e.operands ())
185
+ {
186
+ if (contains_instanceof (subexpr))
187
+ return true ;
188
+ }
189
+
190
+ return false ;
137
191
}
138
192
139
193
// / Replaces expressions like e instanceof A with e.\@class_identifier == "A"
@@ -146,15 +200,20 @@ bool remove_instanceoft::lower_instanceof(
146
200
goto_programt &goto_program,
147
201
goto_programt::targett target)
148
202
{
149
- std::size_t replacements=
150
- lower_instanceof (target->code , goto_program, target)+
151
- lower_instanceof (target->guard , goto_program, target);
203
+ if (target->is_target () &&
204
+ (contains_instanceof (target->code ) || contains_instanceof (target->guard )))
205
+ {
206
+ // If this is a branch target, add a skip beforehand so we can splice new
207
+ // GOTO programs before the target instruction without inserting into the
208
+ // wrong basic block.
209
+ goto_program.insert_before_swap (target);
210
+ target->make_skip ();
211
+ // Actually alter the now-moved instruction:
212
+ ++target;
213
+ }
152
214
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 ;
215
+ return lower_instanceof (target->code , goto_program, target) |
216
+ lower_instanceof (target->guard , goto_program, target);
158
217
}
159
218
160
219
// / Replace every instanceof in the passed function body with an explicit
0 commit comments