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>
22
23
class remove_instanceoft
23
24
{
24
25
public:
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)
27
31
{
28
32
class_hierarchy (symbol_table);
29
33
}
@@ -38,8 +42,9 @@ class remove_instanceoft
38
42
symbol_table_baset &symbol_table;
39
43
namespacet ns;
40
44
class_hierarchyt class_hierarchy;
45
+ message_handlert &message_handler;
41
46
42
- std:: size_t lower_instanceof (
47
+ bool lower_instanceof (
43
48
exprt &, goto_programt &, goto_programt::targett);
44
49
};
45
50
@@ -49,18 +54,18 @@ class remove_instanceoft
49
54
// / \param expr: Expression to lower (the code or the guard of an instruction)
50
55
// / \param goto_program: program the expression belongs to
51
56
// / \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 (
54
59
exprt &expr,
55
60
goto_programt &goto_program,
56
61
goto_programt::targett this_inst)
57
62
{
58
63
if (expr.id ()!=ID_java_instanceof)
59
64
{
60
- std:: size_t replacements= 0 ;
65
+ bool changed = false ;
61
66
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 ;
64
69
}
65
70
66
71
INVARIANT (
@@ -94,46 +99,91 @@ std::size_t remove_instanceoft::lower_instanceof(
94
99
return a.compare (b) < 0 ;
95
100
});
96
101
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
+
104
105
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);
106
107
107
- symbolt &newsym = get_fresh_aux_symbol (
108
+ symbolt &clsid_tmp_sym = get_fresh_aux_symbol (
108
109
object_clsid.type (),
109
110
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" ,
111
120
source_locationt (),
112
121
ID_java,
113
122
symbol_table);
114
123
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" || ...
120
130
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.
124
133
// (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
+
127
146
exprt::operandst or_ops;
128
147
for (const auto &clsname : children)
129
148
{
130
149
constant_exprt clsexpr (clsname, string_typet ());
131
- equal_exprt test (newsym .symbol_expr (), clsexpr);
150
+ equal_exprt test (clsid_tmp_sym .symbol_expr (), clsexpr);
132
151
or_ops.push_back (test);
133
152
}
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 ();
135
160
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 ;
137
187
}
138
188
139
189
// / Replaces expressions like e instanceof A with e.\@class_identifier == "A"
@@ -146,15 +196,20 @@ bool remove_instanceoft::lower_instanceof(
146
196
goto_programt &goto_program,
147
197
goto_programt::targett target)
148
198
{
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
+ }
152
210
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);
158
213
}
159
214
160
215
// / Replace every instanceof in the passed function body with an explicit
@@ -185,12 +240,14 @@ bool remove_instanceoft::lower_instanceof(goto_programt &goto_program)
185
240
// / \param target: The instruction to work on.
186
241
// / \param goto_program: The function body containing the instruction.
187
242
// / \param symbol_table: The symbol table to add symbols to.
243
+ // / \param message_handler: logging output
188
244
void remove_instanceof (
189
245
goto_programt::targett target,
190
246
goto_programt &goto_program,
191
- symbol_table_baset &symbol_table)
247
+ symbol_table_baset &symbol_table,
248
+ message_handlert &message_handler)
192
249
{
193
- remove_instanceoft rem (symbol_table);
250
+ remove_instanceoft rem (symbol_table, message_handler );
194
251
rem.lower_instanceof (goto_program, target);
195
252
}
196
253
@@ -199,11 +256,13 @@ void remove_instanceof(
199
256
// / \remarks Extra auxiliary variables may be introduced into symbol_table.
200
257
// / \param function: The function to work on.
201
258
// / \param symbol_table: The symbol table to add symbols to.
259
+ // / \param message_handler: logging output
202
260
void remove_instanceof (
203
261
goto_functionst::goto_functiont &function,
204
- symbol_table_baset &symbol_table)
262
+ symbol_table_baset &symbol_table,
263
+ message_handlert &message_handler)
205
264
{
206
- remove_instanceoft rem (symbol_table);
265
+ remove_instanceoft rem (symbol_table, message_handler );
207
266
rem.lower_instanceof (function.body );
208
267
}
209
268
@@ -212,11 +271,13 @@ void remove_instanceof(
212
271
// / \remarks Extra auxiliary variables may be introduced into symbol_table.
213
272
// / \param goto_functions: The functions to work on.
214
273
// / \param symbol_table: The symbol table to add symbols to.
274
+ // / \param message_handler: logging output
215
275
void remove_instanceof (
216
276
goto_functionst &goto_functions,
217
- symbol_table_baset &symbol_table)
277
+ symbol_table_baset &symbol_table,
278
+ message_handlert &message_handler)
218
279
{
219
- remove_instanceoft rem (symbol_table);
280
+ remove_instanceoft rem (symbol_table, message_handler );
220
281
bool changed=false ;
221
282
for (auto &f : goto_functions.function_map )
222
283
changed=rem.lower_instanceof (f.second .body ) || changed;
@@ -228,8 +289,12 @@ void remove_instanceof(
228
289
// / class-identifier test.
229
290
// / \remarks Extra auxiliary variables may be introduced into symbol_table.
230
291
// / \param goto_model: The functions to work on and the symbol table to add
292
+ // / \param message_handler: logging output
231
293
// / symbols to.
232
- void remove_instanceof (goto_modelt &goto_model)
294
+ void remove_instanceof (
295
+ goto_modelt &goto_model,
296
+ message_handlert &message_handler)
233
297
{
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);
235
300
}
0 commit comments