|
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