Skip to content

Commit 1e9837e

Browse files
authored
Merge pull request #1405 from smowton/cleanup/remove_instanceof
Clean up remove-instanceof
2 parents 7eb3c76 + 2ddb0bc commit 1e9837e

File tree

2 files changed

+110
-134
lines changed

2 files changed

+110
-134
lines changed

src/goto-programs/goto_program_template.h

+1
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;

src/goto-programs/remove_instanceof.cpp

+109-134
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,160 +43,135 @@ 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-
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
7954
/// 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(
8460
exprt &expr,
8561
goto_programt &goto_program,
86-
goto_programt::targett this_inst,
87-
instanceof_instt &inst_switch)
62+
goto_programt::targett this_inst)
8863
{
89-
if(expr.id()==ID_java_instanceof)
64+
if(expr.id()!=ID_java_instanceof)
9065
{
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;
14370
}
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)
145125
{
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);
148129
}
130+
expr=disjunction(or_ops);
131+
132+
return 1;
149133
}
150134

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(
158142
goto_programt &goto_program,
159-
goto_programt::targett target,
160-
instanceof_instt &inst_switch)
143+
goto_programt::targett target)
161144
{
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;
175154
}
176155

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
181161
bool remove_instanceoft::lower_instanceof(goto_programt &goto_program)
182162
{
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)
187168
{
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;
196170
}
197-
else
171+
if(!changed)
198172
return false;
173+
goto_program.update();
174+
return true;
199175
}
200176

201177
/// See function above
@@ -226,6 +202,5 @@ void remove_instanceof(
226202

227203
void remove_instanceof(goto_modelt &goto_model)
228204
{
229-
remove_instanceof(
230-
goto_model.symbol_table, goto_model.goto_functions);
205+
remove_instanceof(goto_model.symbol_table, goto_model.goto_functions);
231206
}

0 commit comments

Comments
 (0)