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
@@ -50,17 +51,17 @@ class remove_instanceoft
50
51
// / \param goto_program: program the expression belongs to
51
52
// / \param this_inst: instruction the expression is found at
52
53
// / \return number of instanceof expressions that have been replaced
53
- std:: size_t remove_instanceoft::lower_instanceof (
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,93 @@ 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
+ 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);
135
169
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 ;
137
185
}
138
186
139
187
// / Replaces expressions like e instanceof A with e.\@class_identifier == "A"
@@ -146,15 +194,20 @@ bool remove_instanceoft::lower_instanceof(
146
194
goto_programt &goto_program,
147
195
goto_programt::targett target)
148
196
{
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
+ }
152
208
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);
158
211
}
159
212
160
213
// / Replace every instanceof in the passed function body with an explicit
0 commit comments