Skip to content

Commit 75f924a

Browse files
committed
Add remove_instanceof pass
This lowers instanceof binary operators into classid checks, similar to how remove-virtual-functions uses the class ID to build a virtual dispatch table.
1 parent 972c4c7 commit 75f924a

File tree

3 files changed

+299
-1
lines changed

3 files changed

+299
-1
lines changed

src/goto-programs/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ SRC = goto_convert.cpp goto_convert_function_call.cpp \
1818
graphml_witness.cpp remove_virtual_functions.cpp \
1919
class_hierarchy.cpp show_goto_functions.cpp get_goto_model.cpp \
2020
slice_global_inits.cpp goto_inline_class.cpp class_identifier.cpp \
21-
remove_static_init_loops.cpp
21+
remove_static_init_loops.cpp remove_instanceof.cpp
2222

2323
INCLUDES= -I ..
2424

+278
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
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+
}

src/goto-programs/remove_instanceof.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*******************************************************************\
2+
3+
Module: Remove Instance-of Operators
4+
5+
Author: Chris Smowton, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_GOTO_PROGRAMS_REMOVE_INSTANCEOF_H
10+
#define CPROVER_GOTO_PROGRAMS_REMOVE_INSTANCEOF_H
11+
12+
#include <util/symbol_table.h>
13+
#include "goto_functions.h"
14+
15+
void remove_instanceof(
16+
symbol_tablet &symbol_table,
17+
goto_functionst &goto_functions);
18+
19+
20+
#endif

0 commit comments

Comments
 (0)