Skip to content

Commit 2ddb0bc

Browse files
NathanJPhillipssmowton
authored andcommitted
Simplify remove_instanceof logic
Do the swap after each removal rather than in a single pass after each function body
1 parent f763691 commit 2ddb0bc

File tree

1 file changed

+86
-118
lines changed

1 file changed

+86
-118
lines changed

src/goto-programs/remove_instanceof.cpp

+86-118
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Author: Chris Smowton, [email protected]
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,141 +43,114 @@ 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-
7752
/// Replaces an expression like e instanceof A with e.\@class_identifier == "A"
7853
/// or a big-or of similar expressions if we know of subtypes that also satisfy
7954
/// the given test.
8055
/// \param expr: Expression to lower (the code or the guard of an instruction)
8156
/// \param goto_program: program the expression belongs to
8257
/// \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(
58+
/// \return number of instanceof expressions that have been replaced
59+
std::size_t remove_instanceoft::lower_instanceof(
8560
exprt &expr,
8661
goto_programt &goto_program,
87-
goto_programt::targett this_inst,
88-
instanceof_instt &inst_switch)
62+
goto_programt::targett this_inst)
8963
{
9064
if(expr.id()!=ID_java_instanceof)
9165
{
66+
std::size_t replacements=0;
9267
Forall_operands(it, expr)
93-
lower_instanceof(*it, goto_program, this_inst, inst_switch);
94-
return;
68+
replacements+=lower_instanceof(*it, goto_program, this_inst);
69+
return replacements;
70+
}
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)
125+
{
126+
constant_exprt clsexpr(clsname, string_typet());
127+
equal_exprt test(newsym.symbol_expr(), clsexpr);
128+
or_ops.push_back(test);
95129
}
130+
expr=disjunction(or_ops);
96131

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);
132+
return 1;
153133
}
154134

155135
/// Replaces expressions like e instanceof A with e.\@class_identifier == "A"
156136
/// or a big-or of similar expressions if we know of subtypes that also satisfy
157137
/// the given test. Does this for the code or guard at a specific instruction.
158138
/// \param goto_program: program to process
159139
/// \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(
140+
/// \return true if an instanceof has been replaced
141+
bool remove_instanceoft::lower_instanceof(
162142
goto_programt &goto_program,
163-
goto_programt::targett target,
164-
instanceof_instt &inst_switch)
143+
goto_programt::targett target)
165144
{
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);
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;
180154
}
181155

182156
/// Replace every instanceof in the passed function body with an explicit
@@ -186,22 +160,16 @@ void remove_instanceoft::lower_instanceof(
186160
/// \return true if one or more instanceof expressions have been replaced
187161
bool remove_instanceoft::lower_instanceof(goto_programt &goto_program)
188162
{
189-
instanceof_instt inst_switch;
163+
bool changed=false;
190164
for(goto_programt::instructionst::iterator target=
191165
goto_program.instructions.begin();
192166
target!=goto_program.instructions.end();
193167
++target)
194168
{
195-
lower_instanceof(goto_program, target, inst_switch);
169+
changed=lower_instanceof(goto_program, target) || changed;
196170
}
197-
if(inst_switch.empty())
171+
if(!changed)
198172
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-
}
205173
goto_program.update();
206174
return true;
207175
}

0 commit comments

Comments
 (0)