@@ -15,6 +15,7 @@ Author: Chris Smowton, chris.smowton@diffblue.com
1515#include " class_identifier.h"
1616
1717#include < util/fresh_symbol.h>
18+ #include < java_bytecode/java_types.h>
1819
1920#include < sstream>
2021
@@ -42,160 +43,135 @@ class remove_instanceoft
4243
4344 bool lower_instanceof (goto_programt &);
4445
45- typedef std::vector<
46- std::pair<goto_programt::targett, goto_programt::targett>> instanceof_instt;
46+ bool lower_instanceof (goto_programt &, goto_programt::targett);
4747
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);
6050};
6151
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
7954// / 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 (
8460 exprt &expr,
8561 goto_programt &goto_program,
86- goto_programt::targett this_inst,
87- instanceof_instt &inst_switch)
62+ goto_programt::targett this_inst)
8863{
89- if (expr.id ()= =ID_java_instanceof)
64+ if (expr.id ()! =ID_java_instanceof)
9065 {
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;
14370 }
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)
145125 {
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);
148129 }
130+ expr=disjunction (or_ops);
131+
132+ return 1 ;
149133}
150134
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 (
158142 goto_programt &goto_program,
159- goto_programt::targett target,
160- instanceof_instt &inst_switch)
143+ goto_programt::targett target)
161144{
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 ;
175154}
176155
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
181161bool remove_instanceoft::lower_instanceof (goto_programt &goto_program)
182162{
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)
187168 {
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;
196170 }
197- else
171+ if (!changed)
198172 return false ;
173+ goto_program.update ();
174+ return true ;
199175}
200176
201177// / See function above
@@ -226,6 +202,5 @@ void remove_instanceof(
226202
227203void remove_instanceof (goto_modelt &goto_model)
228204{
229- remove_instanceof (
230- goto_model.symbol_table , goto_model.goto_functions );
205+ remove_instanceof (goto_model.symbol_table , goto_model.goto_functions );
231206}
0 commit comments