Skip to content

Commit eaf97f6

Browse files
Simplify remove_instanceof logic
Do the swap after each removal rather than in a single pass after each function body
1 parent 4969295 commit eaf97f6

File tree

1 file changed

+79
-118
lines changed

1 file changed

+79
-118
lines changed

src/goto-programs/remove_instanceof.cpp

+79-118
Original file line numberDiff line numberDiff line change
@@ -42,141 +42,108 @@ class remove_instanceoft
4242

4343
bool lower_instanceof(goto_programt &);
4444

45-
typedef std::vector<
46-
std::pair<goto_programt::targett, goto_programt::targett>> instanceof_instt;
45+
bool lower_instanceof(goto_programt &, goto_programt::targett);
4746

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);
6048
};
6149

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-
7750
/// Replaces an expression like e instanceof A with e.\@class_identifier == "A"
7851
/// or a big-or of similar expressions if we know of subtypes that also satisfy
7952
/// the given test.
8053
/// \param expr: Expression to lower (the code or the guard of an instruction)
8154
/// \param goto_program: program the expression belongs to
8255
/// \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(
56+
/// \return number of instanceof expressions that have been replaced
57+
int remove_instanceoft::lower_instanceof(
8558
exprt &expr,
8659
goto_programt &goto_program,
87-
goto_programt::targett this_inst,
88-
instanceof_instt &inst_switch)
60+
goto_programt::targett this_inst)
8961
{
9062
if(expr.id()!=ID_java_instanceof)
9163
{
64+
int replacements=0;
9265
Forall_operands(it, expr)
93-
lower_instanceof(*it, goto_program, this_inst, inst_switch);
94-
return;
66+
replacements+=lower_instanceof(*it, goto_program, this_inst);
67+
return replacements;
9568
}
9669

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);
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)
118+
{
119+
constant_exprt clsexpr(clsname, string_typet());
120+
equal_exprt test(newsym.symbol_expr(), clsexpr);
121+
or_ops.push_back(test);
122+
}
123+
expr=disjunction(or_ops);
124+
125+
return 1;
153126
}
154127

155128
/// Replaces expressions like e instanceof A with e.\@class_identifier == "A"
156129
/// or a big-or of similar expressions if we know of subtypes that also satisfy
157130
/// the given test. Does this for the code or guard at a specific instruction.
158131
/// \param goto_program: program to process
159132
/// \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(
133+
/// \return true if an instanceof has been replaced
134+
bool remove_instanceoft::lower_instanceof(
162135
goto_programt &goto_program,
163-
goto_programt::targett target,
164-
instanceof_instt &inst_switch)
136+
goto_programt::targett target)
165137
{
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);
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;
180147
}
181148

182149
/// Replace every instanceof in the passed function body with an explicit
@@ -186,22 +153,16 @@ void remove_instanceoft::lower_instanceof(
186153
/// \return true if one or more instanceof expressions have been replaced
187154
bool remove_instanceoft::lower_instanceof(goto_programt &goto_program)
188155
{
189-
instanceof_instt inst_switch;
156+
bool changed=false;
190157
for(goto_programt::instructionst::iterator target=
191158
goto_program.instructions.begin();
192159
target!=goto_program.instructions.end();
193160
++target)
194161
{
195-
lower_instanceof(goto_program, target, inst_switch);
162+
changed=lower_instanceof(goto_program, target) || changed;
196163
}
197-
if(inst_switch.empty())
164+
if(!changed)
198165
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-
}
205166
goto_program.update();
206167
return true;
207168
}

0 commit comments

Comments
 (0)