|
| 1 | +/*******************************************************************\ |
| 2 | +
|
| 3 | +Module: Remove Instance-of Operators |
| 4 | +
|
| 5 | +Author: Chris Smowton, [email protected] |
| 6 | +
|
| 7 | +\*******************************************************************/ |
| 8 | + |
| 9 | +#include "class_hierarchy.h" |
| 10 | +#include "class_identifier.h" |
| 11 | +#include "remove_instanceof.h" |
| 12 | + |
| 13 | +#include <sstream> |
| 14 | + |
| 15 | +class remove_instanceoft |
| 16 | +{ |
| 17 | +public: |
| 18 | + remove_instanceoft( |
| 19 | + symbol_tablet &_symbol_table, |
| 20 | + goto_functionst &_goto_functions): |
| 21 | + symbol_table(_symbol_table), |
| 22 | + ns(_symbol_table), |
| 23 | + goto_functions(_goto_functions), |
| 24 | + lowered_count(0) |
| 25 | + { |
| 26 | + class_hierarchy(_symbol_table); |
| 27 | + } |
| 28 | + |
| 29 | + // Lower instanceof for all functions: |
| 30 | + void lower_instanceof(); |
| 31 | + |
| 32 | +protected: |
| 33 | + symbol_tablet &symbol_table; |
| 34 | + namespacet ns; |
| 35 | + class_hierarchyt class_hierarchy; |
| 36 | + goto_functionst &goto_functions; |
| 37 | + int lowered_count; |
| 38 | + |
| 39 | + bool lower_instanceof(goto_programt &); |
| 40 | + |
| 41 | + typedef std::vector< |
| 42 | + std::pair<goto_programt::targett, goto_programt::targett>> instanceof_instt; |
| 43 | + |
| 44 | + void lower_instanceof( |
| 45 | + goto_programt &, |
| 46 | + goto_programt::targett, |
| 47 | + instanceof_instt &); |
| 48 | + |
| 49 | + void lower_instanceof( |
| 50 | + exprt &, |
| 51 | + goto_programt &, |
| 52 | + goto_programt::targett, |
| 53 | + instanceof_instt &); |
| 54 | + |
| 55 | + bool contains_instanceof(const exprt &); |
| 56 | +}; |
| 57 | + |
| 58 | +/*******************************************************************\ |
| 59 | +
|
| 60 | +Function: remove_instanceoft::contains_instanceof |
| 61 | +
|
| 62 | + Inputs: Expression `expr` |
| 63 | +
|
| 64 | + Outputs: Returns true if `expr` contains any instanceof ops |
| 65 | +
|
| 66 | + Purpose: Avoid breaking sharing by checking for instanceof |
| 67 | + before calling lower_instanceof. |
| 68 | +
|
| 69 | +\*******************************************************************/ |
| 70 | + |
| 71 | +bool remove_instanceoft::contains_instanceof( |
| 72 | + const exprt &expr) |
| 73 | +{ |
| 74 | + if(expr.id()==ID_java_instanceof) |
| 75 | + return true; |
| 76 | + forall_operands(it, expr) |
| 77 | + if(contains_instanceof(*it)) |
| 78 | + return true; |
| 79 | + return false; |
| 80 | +} |
| 81 | + |
| 82 | +/*******************************************************************\ |
| 83 | +
|
| 84 | +Function: remove_instanceoft::lower_instanceof |
| 85 | +
|
| 86 | + Inputs: Expression to lower `expr` and the `goto_program` and |
| 87 | + instruction `this_inst` it belongs to. |
| 88 | +
|
| 89 | + Outputs: Side-effect on `expr` replacing it with an explicit clsid test |
| 90 | +
|
| 91 | + Purpose: Replaces an expression like |
| 92 | + e instanceof A |
| 93 | + with |
| 94 | + e.@class_identifier == "A" |
| 95 | + Or a big-or of similar expressions if we know of subtypes |
| 96 | + that also satisfy the given test. |
| 97 | +
|
| 98 | +\*******************************************************************/ |
| 99 | + |
| 100 | +void remove_instanceoft::lower_instanceof( |
| 101 | + exprt &expr, |
| 102 | + goto_programt &goto_program, |
| 103 | + goto_programt::targett this_inst, |
| 104 | + instanceof_instt &inst_switch) |
| 105 | +{ |
| 106 | + if(expr.id()==ID_java_instanceof) |
| 107 | + { |
| 108 | + const exprt &check_ptr=expr.op0(); |
| 109 | + assert(check_ptr.type().id()==ID_pointer); |
| 110 | + const exprt &target_arg=expr.op1(); |
| 111 | + assert(target_arg.id()==ID_type); |
| 112 | + const typet &target_type=target_arg.type(); |
| 113 | + |
| 114 | + // Find all types we know about that satisfy the given requirement: |
| 115 | + assert(target_type.id()==ID_symbol); |
| 116 | + const irep_idt &target_name= |
| 117 | + to_symbol_type(target_type).get_identifier(); |
| 118 | + std::vector<irep_idt> children= |
| 119 | + class_hierarchy.get_children_trans(target_name); |
| 120 | + children.push_back(target_name); |
| 121 | + |
| 122 | + assert(!children.empty() && "Unable to execute instanceof"); |
| 123 | + |
| 124 | + // Insert an instruction before this one that assigns the clsid we're |
| 125 | + // checking against to a temporary, as GOTO program if-expressions should |
| 126 | + // not contain derefs. |
| 127 | + |
| 128 | + symbol_typet jlo("java::java.lang.Object"); |
| 129 | + exprt object_clsid=get_class_identifier_field(check_ptr, jlo, ns); |
| 130 | + |
| 131 | + std::ostringstream symname; |
| 132 | + symname << "instanceof_tmp::instanceof_tmp" << (++lowered_count); |
| 133 | + auxiliary_symbolt newsym; |
| 134 | + newsym.name=symname.str(); |
| 135 | + newsym.type=object_clsid.type(); |
| 136 | + newsym.base_name=newsym.name; |
| 137 | + newsym.mode=ID_java; |
| 138 | + newsym.is_type=false; |
| 139 | + assert(!symbol_table.add(newsym)); |
| 140 | + |
| 141 | + auto newinst=goto_program.insert_after(this_inst); |
| 142 | + newinst->make_assignment(); |
| 143 | + newinst->code=code_assignt(newsym.symbol_expr(), object_clsid); |
| 144 | + newinst->source_location=this_inst->source_location; |
| 145 | + |
| 146 | + // Insert the check instruction after the existing one. |
| 147 | + // This will briefly be ill-formed (use before def of |
| 148 | + // instanceof_tmp) but the two will subsequently switch |
| 149 | + // places in lower_instanceof(goto_programt &) below. |
| 150 | + inst_switch.push_back(make_pair(this_inst, newinst)); |
| 151 | + // Replace the instanceof construct with a big-or. |
| 152 | + exprt::operandst or_ops; |
| 153 | + for(const auto &clsname : children) |
| 154 | + { |
| 155 | + constant_exprt clsexpr(clsname, string_typet()); |
| 156 | + equal_exprt test(newsym.symbol_expr(), clsexpr); |
| 157 | + or_ops.push_back(test); |
| 158 | + } |
| 159 | + expr=disjunction(or_ops); |
| 160 | + } |
| 161 | + else |
| 162 | + { |
| 163 | + Forall_operands(it, expr) |
| 164 | + lower_instanceof(*it, goto_program, this_inst, inst_switch); |
| 165 | + } |
| 166 | +} |
| 167 | + |
| 168 | +/*******************************************************************\ |
| 169 | +
|
| 170 | +Function: remove_instanceoft::lower_instanceof |
| 171 | +
|
| 172 | + Inputs: GOTO program instruction `target` whose instanceof expressions, |
| 173 | + if any, should be replaced with explicit tests, and the |
| 174 | + `goto_program` it is part of. |
| 175 | +
|
| 176 | + Outputs: Side-effect on `target` as above. |
| 177 | +
|
| 178 | + Purpose: See function above |
| 179 | +
|
| 180 | +\*******************************************************************/ |
| 181 | + |
| 182 | +void remove_instanceoft::lower_instanceof( |
| 183 | + goto_programt &goto_program, |
| 184 | + goto_programt::targett target, |
| 185 | + instanceof_instt &inst_switch) |
| 186 | +{ |
| 187 | + bool code_iof=contains_instanceof(target->code); |
| 188 | + bool guard_iof=contains_instanceof(target->guard); |
| 189 | + // The instruction-switching step below will malfunction if a check |
| 190 | + // has been added for the code *and* for the guard. This should |
| 191 | + // be impossible, because guarded instructions currently have simple |
| 192 | + // code (e.g. a guarded-goto), but this assertion checks that this |
| 193 | + // assumption is correct and remains true on future evolution of the |
| 194 | + // allowable goto instruction types. |
| 195 | + assert(!(code_iof && guard_iof)); |
| 196 | + if(code_iof) |
| 197 | + lower_instanceof(target->code, goto_program, target, inst_switch); |
| 198 | + if(guard_iof) |
| 199 | + lower_instanceof(target->guard, goto_program, target, inst_switch); |
| 200 | +} |
| 201 | + |
| 202 | +/*******************************************************************\ |
| 203 | +
|
| 204 | +Function: remove_instanceoft::lower_instanceof |
| 205 | +
|
| 206 | + Inputs: `goto_program`, all of whose instanceof expressions will |
| 207 | + be replaced by explicit class-identifier tests. |
| 208 | +
|
| 209 | + Outputs: Side-effect on `goto_program` as above. |
| 210 | +
|
| 211 | + Purpose: See function above |
| 212 | +
|
| 213 | +\*******************************************************************/ |
| 214 | +bool remove_instanceoft::lower_instanceof(goto_programt &goto_program) |
| 215 | +{ |
| 216 | + instanceof_instt inst_switch; |
| 217 | + Forall_goto_program_instructions(target, goto_program) |
| 218 | + lower_instanceof(goto_program, target, inst_switch); |
| 219 | + if(!inst_switch.empty()) |
| 220 | + { |
| 221 | + for(auto &p : inst_switch) |
| 222 | + { |
| 223 | + const goto_programt::targett &this_inst=p.first; |
| 224 | + const goto_programt::targett &newinst=p.second; |
| 225 | + this_inst->swap(*newinst); |
| 226 | + } |
| 227 | + goto_program.update(); |
| 228 | + return true; |
| 229 | + } |
| 230 | + else |
| 231 | + return false; |
| 232 | +} |
| 233 | + |
| 234 | +/*******************************************************************\ |
| 235 | +
|
| 236 | +Function: remove_instanceoft::lower_instanceof |
| 237 | +
|
| 238 | + Inputs: None |
| 239 | +
|
| 240 | + Outputs: Side-effects on this->goto_functions, replacing every |
| 241 | + instanceof in every function with an explicit test. |
| 242 | +
|
| 243 | + Purpose: See function above |
| 244 | +
|
| 245 | +\*******************************************************************/ |
| 246 | + |
| 247 | +void remove_instanceoft::lower_instanceof() |
| 248 | +{ |
| 249 | + bool changed=false; |
| 250 | + for(auto &f : goto_functions.function_map) |
| 251 | + changed=(lower_instanceof(f.second.body) || changed); |
| 252 | + if(changed) |
| 253 | + goto_functions.compute_location_numbers(); |
| 254 | +} |
| 255 | + |
| 256 | +/*******************************************************************\ |
| 257 | +
|
| 258 | +Function: remove_instanceof |
| 259 | +
|
| 260 | + Inputs: `goto_functions`, a function map, and the corresponding |
| 261 | + `symbol_table`. |
| 262 | +
|
| 263 | + Outputs: Side-effects on goto_functions, replacing every |
| 264 | + instanceof in every function with an explicit test. |
| 265 | + Extra auxiliary variables may be introduced into |
| 266 | + `symbol_table`. |
| 267 | +
|
| 268 | + Purpose: See function above |
| 269 | +
|
| 270 | +\*******************************************************************/ |
| 271 | + |
| 272 | +void remove_instanceof( |
| 273 | + symbol_tablet &symbol_table, |
| 274 | + goto_functionst &goto_functions) |
| 275 | +{ |
| 276 | + remove_instanceoft rem(symbol_table, goto_functions); |
| 277 | + rem.lower_instanceof(); |
| 278 | +} |
0 commit comments