Skip to content

Commit 101d81a

Browse files
Merge pull request diffblue#194 from diffblue/cleanup/remove_instanceof
Tidy up remove_instanceof
2 parents fd17982 + 99d9619 commit 101d81a

File tree

2 files changed

+103
-134
lines changed

2 files changed

+103
-134
lines changed

cbmc/src/goto-programs/goto_program_template.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ class goto_program_templatet
361361
}
362362
};
363363

364+
// Never try to change this to vector-we mutate the list while iterating
364365
typedef std::list<instructiont> instructionst;
365366

366367
typedef typename instructionst::iterator targett;

cbmc/src/goto-programs/remove_instanceof.cpp

Lines changed: 102 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -42,160 +42,129 @@ 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-
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
50+
/// Replaces an expression like e instanceof A with e.\@class_identifier == "A"
51+
/// or a big-or of similar expressions if we know of subtypes that also satisfy
7952
/// 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(
53+
/// \param expr: Expression to lower (the code or the guard of an instruction)
54+
/// \param goto_program: program the expression belongs to
55+
/// \param this_inst: instruction the expression is found at
56+
/// \return number of instanceof expressions that have been replaced
57+
int remove_instanceoft::lower_instanceof(
8458
exprt &expr,
8559
goto_programt &goto_program,
86-
goto_programt::targett this_inst,
87-
instanceof_instt &inst_switch)
60+
goto_programt::targett this_inst)
8861
{
89-
if(expr.id()==ID_java_instanceof)
62+
if(expr.id()!=ID_java_instanceof)
9063
{
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);
64+
int replacements=0;
65+
Forall_operands(it, expr)
66+
replacements+=lower_instanceof(*it, goto_program, this_inst);
67+
return replacements;
14368
}
144-
else
69+
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)
145118
{
146-
Forall_operands(it, expr)
147-
lower_instanceof(*it, goto_program, this_inst, inst_switch);
119+
constant_exprt clsexpr(clsname, string_typet());
120+
equal_exprt test(newsym.symbol_expr(), clsexpr);
121+
or_ops.push_back(test);
148122
}
123+
expr=disjunction(or_ops);
124+
125+
return 1;
149126
}
150127

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(
128+
/// Replaces expressions like e instanceof A with e.\@class_identifier == "A"
129+
/// or a big-or of similar expressions if we know of subtypes that also satisfy
130+
/// the given test. Does this for the code or guard at a specific instruction.
131+
/// \param goto_program: program to process
132+
/// \param target: instruction to check for instanceof expressions
133+
/// \return true if an instanceof has been replaced
134+
bool remove_instanceoft::lower_instanceof(
158135
goto_programt &goto_program,
159-
goto_programt::targett target,
160-
instanceof_instt &inst_switch)
136+
goto_programt::targett target)
161137
{
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);
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;
175147
}
176148

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.
149+
/// Replace every instanceof in the passed function body with an explicit
150+
/// class-identifier test.
151+
/// Extra auxiliary variables may be introduced into symbol_table.
152+
/// \param goto_program: The function body to work on.
153+
/// \return true if one or more instanceof expressions have been replaced
181154
bool remove_instanceoft::lower_instanceof(goto_programt &goto_program)
182155
{
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())
156+
bool changed=false;
157+
for(goto_programt::instructionst::iterator target=
158+
goto_program.instructions.begin();
159+
target!=goto_program.instructions.end();
160+
++target)
187161
{
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;
162+
changed=lower_instanceof(goto_program, target) || changed;
196163
}
197-
else
164+
if(!changed)
198165
return false;
166+
goto_program.update();
167+
return true;
199168
}
200169

201170
/// See function above
@@ -226,6 +195,5 @@ void remove_instanceof(
226195

227196
void remove_instanceof(goto_modelt &goto_model)
228197
{
229-
remove_instanceof(
230-
goto_model.symbol_table, goto_model.goto_functions);
198+
remove_instanceof(goto_model.symbol_table, goto_model.goto_functions);
231199
}

0 commit comments

Comments
 (0)