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