@@ -15,6 +15,7 @@ Author: Chris Smowton, chris.smowton@diffblue.com
15
15
#include " class_identifier.h"
16
16
17
17
#include < util/fresh_symbol.h>
18
+ #include < java_bytecode/java_types.h>
18
19
19
20
#include < sstream>
20
21
@@ -42,160 +43,135 @@ class remove_instanceoft
42
43
43
44
bool lower_instanceof (goto_programt &);
44
45
45
- typedef std::vector<
46
- std::pair<goto_programt::targett, goto_programt::targett>> instanceof_instt;
46
+ bool lower_instanceof (goto_programt &, goto_programt::targett);
47
47
48
- void lower_instanceof (
49
- goto_programt &,
50
- goto_programt::targett,
51
- instanceof_instt &);
52
-
53
- void lower_instanceof (
54
- exprt &,
55
- goto_programt &,
56
- goto_programt::targett,
57
- instanceof_instt &);
58
-
59
- bool contains_instanceof (const exprt &);
48
+ std::size_t lower_instanceof (
49
+ exprt &, goto_programt &, goto_programt::targett);
60
50
};
61
51
62
- // / Avoid breaking sharing by checking for instanceof before calling
63
- // / lower_instanceof.
64
- // / \par parameters: Expression `expr`
65
- // / \return Returns true if `expr` contains any instanceof ops
66
- bool remove_instanceoft::contains_instanceof (
67
- const exprt &expr)
68
- {
69
- if (expr.id ()==ID_java_instanceof)
70
- return true ;
71
- forall_operands (it, expr)
72
- if (contains_instanceof (*it))
73
- return true ;
74
- return false ;
75
- }
76
-
77
- // / Replaces an expression like e instanceof A with e.@class_identifier == "A"
78
- // / Or a big-or of similar expressions if we know of subtypes that also satisfy
52
+ // / Replaces an expression like e instanceof A with e.\@class_identifier == "A"
53
+ // / or a big-or of similar expressions if we know of subtypes that also satisfy
79
54
// / the given test.
80
- // / \par parameters: Expression to lower `expr` and the `goto_program` and
81
- // / instruction `this_inst` it belongs to.
82
- // / \return Side-effect on `expr` replacing it with an explicit clsid test
83
- void remove_instanceoft::lower_instanceof (
55
+ // / \param expr: Expression to lower (the code or the guard of an instruction)
56
+ // / \param goto_program: program the expression belongs to
57
+ // / \param this_inst: instruction the expression is found at
58
+ // / \return number of instanceof expressions that have been replaced
59
+ std::size_t remove_instanceoft::lower_instanceof (
84
60
exprt &expr,
85
61
goto_programt &goto_program,
86
- goto_programt::targett this_inst,
87
- instanceof_instt &inst_switch)
62
+ goto_programt::targett this_inst)
88
63
{
89
- if (expr.id ()= =ID_java_instanceof)
64
+ if (expr.id ()! =ID_java_instanceof)
90
65
{
91
- const exprt &check_ptr=expr.op0 ();
92
- assert (check_ptr.type ().id ()==ID_pointer);
93
- const exprt &target_arg=expr.op1 ();
94
- assert (target_arg.id ()==ID_type);
95
- const typet &target_type=target_arg.type ();
96
-
97
- // Find all types we know about that satisfy the given requirement:
98
- assert (target_type.id ()==ID_symbol);
99
- const irep_idt &target_name=
100
- to_symbol_type (target_type).get_identifier ();
101
- std::vector<irep_idt> children=
102
- class_hierarchy.get_children_trans (target_name);
103
- children.push_back (target_name);
104
-
105
- assert (!children.empty () && " Unable to execute instanceof" );
106
-
107
- // Insert an instruction before this one that assigns the clsid we're
108
- // checking against to a temporary, as GOTO program if-expressions should
109
- // not contain derefs.
110
-
111
- symbol_typet jlo (" java::java.lang.Object" );
112
- exprt object_clsid=get_class_identifier_field (check_ptr, jlo, ns);
113
-
114
- symbolt &newsym=
115
- get_fresh_aux_symbol (
116
- object_clsid.type (),
117
- " instanceof_tmp" ,
118
- " instanceof_tmp" ,
119
- source_locationt (),
120
- ID_java,
121
- symbol_table);
122
-
123
- auto newinst=goto_program.insert_after (this_inst);
124
- newinst->make_assignment ();
125
- newinst->code =code_assignt (newsym.symbol_expr (), object_clsid);
126
- newinst->source_location =this_inst->source_location ;
127
- newinst->function =this_inst->function ;
128
-
129
- // Insert the check instruction after the existing one.
130
- // This will briefly be ill-formed (use before def of
131
- // instanceof_tmp) but the two will subsequently switch
132
- // places in lower_instanceof(goto_programt &) below.
133
- inst_switch.push_back (make_pair (this_inst, newinst));
134
- // Replace the instanceof construct with a big-or.
135
- exprt::operandst or_ops;
136
- for (const auto &clsname : children)
137
- {
138
- constant_exprt clsexpr (clsname, string_typet ());
139
- equal_exprt test (newsym.symbol_expr (), clsexpr);
140
- or_ops.push_back (test);
141
- }
142
- expr=disjunction (or_ops);
66
+ std::size_t replacements=0 ;
67
+ Forall_operands (it, expr)
68
+ replacements+=lower_instanceof (*it, goto_program, this_inst);
69
+ return replacements;
143
70
}
144
- else
71
+
72
+ INVARIANT (
73
+ expr.operands ().size ()==2 ,
74
+ " java_instanceof should have two operands" );
75
+
76
+ const exprt &check_ptr=expr.op0 ();
77
+ INVARIANT (
78
+ check_ptr.type ().id ()==ID_pointer,
79
+ " instanceof first operand should be a pointer" );
80
+
81
+ const exprt &target_arg=expr.op1 ();
82
+ INVARIANT (
83
+ target_arg.id ()==ID_type,
84
+ " instanceof second operand should be a type" );
85
+ const typet &target_type=target_arg.type ();
86
+
87
+ // Find all types we know about that satisfy the given requirement:
88
+ INVARIANT (
89
+ target_type.id ()==ID_symbol,
90
+ " instanceof second operand should have a simple type" );
91
+ const irep_idt &target_name=
92
+ to_symbol_type (target_type).get_identifier ();
93
+ std::vector<irep_idt> children=
94
+ class_hierarchy.get_children_trans (target_name);
95
+ children.push_back (target_name);
96
+
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.
104
+ symbol_typet jlo=to_symbol_type (java_lang_object_type ().subtype ());
105
+ exprt object_clsid=get_class_identifier_field (check_ptr, jlo, ns);
106
+
107
+ symbolt &newsym=
108
+ get_fresh_aux_symbol (
109
+ object_clsid.type (),
110
+ " instanceof_tmp" ,
111
+ " instanceof_tmp" ,
112
+ source_locationt (),
113
+ ID_java,
114
+ symbol_table);
115
+
116
+ auto newinst=goto_program.insert_after (this_inst);
117
+ newinst->make_assignment ();
118
+ newinst->code =code_assignt (newsym.symbol_expr (), object_clsid);
119
+ newinst->source_location =this_inst->source_location ;
120
+ newinst->function =this_inst->function ;
121
+
122
+ // Replace the instanceof construct with a big-or.
123
+ exprt::operandst or_ops;
124
+ for (const auto &clsname : children)
145
125
{
146
- Forall_operands (it, expr)
147
- lower_instanceof (*it, goto_program, this_inst, inst_switch);
126
+ constant_exprt clsexpr (clsname, string_typet ());
127
+ equal_exprt test (newsym.symbol_expr (), clsexpr);
128
+ or_ops.push_back (test);
148
129
}
130
+ expr=disjunction (or_ops);
131
+
132
+ return 1 ;
149
133
}
150
134
151
- // / See function above
152
- // / \par parameters: GOTO program instruction `target` whose instanceof
153
- // / expressions,
154
- // / if any, should be replaced with explicit tests, and the
155
- // / `goto_program` it is part of.
156
- // / \return Side-effect on `target` as above.
157
- void remove_instanceoft::lower_instanceof (
135
+ // / Replaces expressions like e instanceof A with e.\@class_identifier == "A"
136
+ // / or a big-or of similar expressions if we know of subtypes that also satisfy
137
+ // / the given test. Does this for the code or guard at a specific instruction.
138
+ // / \param goto_program: program to process
139
+ // / \param target: instruction to check for instanceof expressions
140
+ // / \return true if an instanceof has been replaced
141
+ bool remove_instanceoft::lower_instanceof (
158
142
goto_programt &goto_program,
159
- goto_programt::targett target,
160
- instanceof_instt &inst_switch)
143
+ goto_programt::targett target)
161
144
{
162
- bool code_iof=contains_instanceof (target->code );
163
- bool guard_iof=contains_instanceof (target->guard );
164
- // The instruction-switching step below will malfunction if a check
165
- // has been added for the code *and* for the guard. This should
166
- // be impossible, because guarded instructions currently have simple
167
- // code (e.g. a guarded-goto), but this assertion checks that this
168
- // assumption is correct and remains true on future evolution of the
169
- // allowable goto instruction types.
170
- assert (!(code_iof && guard_iof));
171
- if (code_iof)
172
- lower_instanceof (target->code , goto_program, target, inst_switch);
173
- if (guard_iof)
174
- lower_instanceof (target->guard , goto_program, target, inst_switch);
145
+ std::size_t replacements=
146
+ lower_instanceof (target->code , goto_program, target)+
147
+ lower_instanceof (target->guard , goto_program, target);
148
+
149
+ if (replacements==0 )
150
+ return false ;
151
+ // Swap the original instruction with the last assignment added after it
152
+ target->swap (*std::next (target, replacements));
153
+ return true ;
175
154
}
176
155
177
- // / See function above
178
- // / \par parameters: `goto_program`, all of whose instanceof expressions will
179
- // / be replaced by explicit class-identifier tests.
180
- // / \return Side-effect on `goto_program` as above.
156
+ // / Replace every instanceof in the passed function body with an explicit
157
+ // / class-identifier test.
158
+ // / Extra auxiliary variables may be introduced into symbol_table.
159
+ // / \param goto_program: The function body to work on.
160
+ // / \return true if one or more instanceof expressions have been replaced
181
161
bool remove_instanceoft::lower_instanceof (goto_programt &goto_program)
182
162
{
183
- instanceof_instt inst_switch;
184
- Forall_goto_program_instructions (target, goto_program)
185
- lower_instanceof (goto_program, target, inst_switch);
186
- if (!inst_switch.empty ())
163
+ bool changed=false ;
164
+ for (goto_programt::instructionst::iterator target=
165
+ goto_program.instructions .begin ();
166
+ target!=goto_program.instructions .end ();
167
+ ++target)
187
168
{
188
- for (auto &p : inst_switch)
189
- {
190
- const goto_programt::targett &this_inst=p.first ;
191
- const goto_programt::targett &newinst=p.second ;
192
- this_inst->swap (*newinst);
193
- }
194
- goto_program.update ();
195
- return true ;
169
+ changed=lower_instanceof (goto_program, target) || changed;
196
170
}
197
- else
171
+ if (!changed)
198
172
return false ;
173
+ goto_program.update ();
174
+ return true ;
199
175
}
200
176
201
177
// / See function above
@@ -226,6 +202,5 @@ void remove_instanceof(
226
202
227
203
void remove_instanceof (goto_modelt &goto_model)
228
204
{
229
- remove_instanceof (
230
- goto_model.symbol_table , goto_model.goto_functions );
205
+ remove_instanceof (goto_model.symbol_table , goto_model.goto_functions );
231
206
}
0 commit comments