@@ -42,160 +42,129 @@ 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
- // / 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
50
+ // / Replaces an expression like e instanceof A with e.\@class_identifier == "A"
51
+ // / or a big-or of similar expressions if we know of subtypes that also satisfy
79
52
// / 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 (
53
+ // / \param expr: Expression to lower (the code or the guard of an instruction)
54
+ // / \param goto_program: program the expression belongs to
55
+ // / \param this_inst: instruction the expression is found at
56
+ // / \return number of instanceof expressions that have been replaced
57
+ int remove_instanceoft::lower_instanceof (
84
58
exprt &expr,
85
59
goto_programt &goto_program,
86
- goto_programt::targett this_inst,
87
- instanceof_instt &inst_switch)
60
+ goto_programt::targett this_inst)
88
61
{
89
- if (expr.id ()= =ID_java_instanceof)
62
+ if (expr.id ()! =ID_java_instanceof)
90
63
{
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);
64
+ int replacements=0 ;
65
+ Forall_operands (it, expr)
66
+ replacements+=lower_instanceof (*it, goto_program, this_inst);
67
+ return replacements;
143
68
}
144
- else
69
+
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)
145
118
{
146
- Forall_operands (it, expr)
147
- lower_instanceof (*it, goto_program, this_inst, inst_switch);
119
+ constant_exprt clsexpr (clsname, string_typet ());
120
+ equal_exprt test (newsym.symbol_expr (), clsexpr);
121
+ or_ops.push_back (test);
148
122
}
123
+ expr=disjunction (or_ops);
124
+
125
+ return 1 ;
149
126
}
150
127
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 (
128
+ // / Replaces expressions like e instanceof A with e.\@class_identifier == "A"
129
+ // / or a big-or of similar expressions if we know of subtypes that also satisfy
130
+ // / the given test. Does this for the code or guard at a specific instruction.
131
+ // / \param goto_program: program to process
132
+ // / \param target: instruction to check for instanceof expressions
133
+ // / \return true if an instanceof has been replaced
134
+ bool remove_instanceoft::lower_instanceof (
158
135
goto_programt &goto_program,
159
- goto_programt::targett target,
160
- instanceof_instt &inst_switch)
136
+ goto_programt::targett target)
161
137
{
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);
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 ;
175
147
}
176
148
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.
149
+ // / Replace every instanceof in the passed function body with an explicit
150
+ // / class-identifier test.
151
+ // / Extra auxiliary variables may be introduced into symbol_table.
152
+ // / \param goto_program: The function body to work on.
153
+ // / \return true if one or more instanceof expressions have been replaced
181
154
bool remove_instanceoft::lower_instanceof (goto_programt &goto_program)
182
155
{
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 ())
156
+ bool changed=false ;
157
+ for (goto_programt::instructionst::iterator target=
158
+ goto_program.instructions .begin ();
159
+ target!=goto_program.instructions .end ();
160
+ ++target)
187
161
{
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 ;
162
+ changed=lower_instanceof (goto_program, target) || changed;
196
163
}
197
- else
164
+ if (!changed)
198
165
return false ;
166
+ goto_program.update ();
167
+ return true ;
199
168
}
200
169
201
170
// / See function above
@@ -226,6 +195,5 @@ void remove_instanceof(
226
195
227
196
void remove_instanceof (goto_modelt &goto_model)
228
197
{
229
- remove_instanceof (
230
- goto_model.symbol_table , goto_model.goto_functions );
198
+ remove_instanceof (goto_model.symbol_table , goto_model.goto_functions );
231
199
}
0 commit comments