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,141 +43,114 @@ 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
52
// / Replaces an expression like e instanceof A with e.\@class_identifier == "A"
78
53
// / or a big-or of similar expressions if we know of subtypes that also satisfy
79
54
// / the given test.
80
55
// / \param expr: Expression to lower (the code or the guard of an instruction)
81
56
// / \param goto_program: program the expression belongs to
82
57
// / \param this_inst: instruction the expression is found at
83
- // / \param inst_switch: set of instructions to switch around once we're done
84
- void remove_instanceoft::lower_instanceof (
58
+ // / \return number of instanceof expressions that have been replaced
59
+ std:: size_t remove_instanceoft::lower_instanceof (
85
60
exprt &expr,
86
61
goto_programt &goto_program,
87
- goto_programt::targett this_inst,
88
- instanceof_instt &inst_switch)
62
+ goto_programt::targett this_inst)
89
63
{
90
64
if (expr.id ()!=ID_java_instanceof)
91
65
{
66
+ std::size_t replacements=0 ;
92
67
Forall_operands (it, expr)
93
- lower_instanceof (*it, goto_program, this_inst, inst_switch);
94
- return ;
68
+ replacements+=lower_instanceof (*it, goto_program, this_inst);
69
+ return replacements;
70
+ }
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)
125
+ {
126
+ constant_exprt clsexpr (clsname, string_typet ());
127
+ equal_exprt test (newsym.symbol_expr (), clsexpr);
128
+ or_ops.push_back (test);
95
129
}
130
+ expr=disjunction (or_ops);
96
131
97
- const exprt &check_ptr=expr.op0 ();
98
- INVARIANT (
99
- check_ptr.type ().id ()==ID_pointer,
100
- " instanceof first operand should be a pointer" );
101
- const exprt &target_arg=expr.op1 ();
102
- INVARIANT (
103
- target_arg.id ()==ID_type,
104
- " instanceof second operand should be a type" );
105
- const typet &target_type=target_arg.type ();
106
-
107
- // Find all types we know about that satisfy the given requirement:
108
- INVARIANT (
109
- target_type.id ()==ID_symbol,
110
- " instanceof second operand should have a simple type" );
111
- const irep_idt &target_name=
112
- to_symbol_type (target_type).get_identifier ();
113
- std::vector<irep_idt> children=
114
- class_hierarchy.get_children_trans (target_name);
115
- children.push_back (target_name);
116
-
117
- // Insert an instruction before the new check that assigns the clsid we're
118
- // checking for to a temporary, as GOTO program if-expressions should
119
- // not contain derefs.
120
- // We actually insert the assignment instruction after the existing one.
121
- // This will briefly be ill-formed (use before def of instanceof_tmp) but the
122
- // two will subsequently switch places. This makes sure that the inserted
123
- // assignement doesn't end up before any labels pointing at this instruction.
124
- symbol_typet jlo (" java::java.lang.Object" );
125
- exprt object_clsid=get_class_identifier_field (check_ptr, jlo, ns);
126
-
127
- symbolt &newsym=
128
- get_fresh_aux_symbol (
129
- object_clsid.type (),
130
- " instanceof_tmp" ,
131
- " instanceof_tmp" ,
132
- source_locationt (),
133
- ID_java,
134
- symbol_table);
135
-
136
- auto newinst=goto_program.insert_after (this_inst);
137
- newinst->make_assignment ();
138
- newinst->code =code_assignt (newsym.symbol_expr (), object_clsid);
139
- newinst->source_location =this_inst->source_location ;
140
- newinst->function =this_inst->function ;
141
-
142
- // Remember to switch the instructions
143
- inst_switch.push_back (make_pair (this_inst, newinst));
144
- // Replace the instanceof construct with a big-or.
145
- exprt::operandst or_ops;
146
- for (const auto &clsname : children)
147
- {
148
- constant_exprt clsexpr (clsname, string_typet ());
149
- equal_exprt test (newsym.symbol_expr (), clsexpr);
150
- or_ops.push_back (test);
151
- }
152
- expr=disjunction (or_ops);
132
+ return 1 ;
153
133
}
154
134
155
135
// / Replaces expressions like e instanceof A with e.\@class_identifier == "A"
156
136
// / or a big-or of similar expressions if we know of subtypes that also satisfy
157
137
// / the given test. Does this for the code or guard at a specific instruction.
158
138
// / \param goto_program: program to process
159
139
// / \param target: instruction to check for instanceof expressions
160
- // / \param inst_switch: set of instructions to switch around once we're done
161
- void remove_instanceoft::lower_instanceof (
140
+ // / \return true if an instanceof has been replaced
141
+ bool remove_instanceoft::lower_instanceof (
162
142
goto_programt &goto_program,
163
- goto_programt::targett target,
164
- instanceof_instt &inst_switch)
143
+ goto_programt::targett target)
165
144
{
166
- bool code_iof=contains_instanceof (target->code );
167
- bool guard_iof=contains_instanceof (target->guard );
168
- // The instruction-switching step below will malfunction if a check
169
- // has been added for the code *and* for the guard. This should
170
- // be impossible, because guarded instructions currently have simple
171
- // code (e.g. a guarded-goto), but this assertion checks that this
172
- // assumption is correct and remains true on future evolution of the
173
- // allowable goto instruction types.
174
- INVARIANT (
175
- !(code_iof && guard_iof), " instanceof code should not have a guard" );
176
- if (code_iof)
177
- lower_instanceof (target->code , goto_program, target, inst_switch);
178
- if (guard_iof)
179
- 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 ;
180
154
}
181
155
182
156
// / Replace every instanceof in the passed function body with an explicit
@@ -186,22 +160,16 @@ void remove_instanceoft::lower_instanceof(
186
160
// / \return true if one or more instanceof expressions have been replaced
187
161
bool remove_instanceoft::lower_instanceof (goto_programt &goto_program)
188
162
{
189
- instanceof_instt inst_switch ;
163
+ bool changed= false ;
190
164
for (goto_programt::instructionst::iterator target=
191
165
goto_program.instructions .begin ();
192
166
target!=goto_program.instructions .end ();
193
167
++target)
194
168
{
195
- lower_instanceof (goto_program, target, inst_switch) ;
169
+ changed= lower_instanceof (goto_program, target) || changed ;
196
170
}
197
- if (inst_switch. empty () )
171
+ if (!changed )
198
172
return false ;
199
- for (auto &p : inst_switch)
200
- {
201
- const goto_programt::targett &this_inst=p.first ;
202
- const goto_programt::targett &newinst=p.second ;
203
- this_inst->swap (*newinst);
204
- }
205
173
goto_program.update ();
206
174
return true ;
207
175
}
0 commit comments