Skip to content

Commit d9122dc

Browse files
authored
Merge pull request diffblue#1710 from NathanJPhillips/feature/remove_instanceof_per_function
Allow to remove instanceof when remove exceptions
2 parents 1c227b7 + c8821b2 commit d9122dc

File tree

5 files changed

+111
-65
lines changed

5 files changed

+111
-65
lines changed

src/goto-programs/remove_exceptions.cpp

+65-54
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Date: December 2016
1212
/// Remove exception handling
1313

1414
#include "remove_exceptions.h"
15+
#include "remove_instanceof.h"
1516

1617
#ifdef DEBUG
1718
#include <iostream>
@@ -43,8 +44,9 @@ Date: December 2016
4344
/// (in instruction->code.exception_list()) and a corresponding GOTO program
4445
/// target for each (in instruction->targets).
4546
/// Thrown instructions are currently always matched to tags using
46-
/// java_instanceof, so a language frontend wanting to use this class
47-
/// must use exceptions with a Java-compatible structure.
47+
/// java_instanceof, optionally lowered to a check on the @class_identifier
48+
/// field, so a language frontend wanting to use this class must use
49+
/// exceptions with a Java-compatible structure.
4850
///
4951
/// CATCH with a code_pop_catcht operand terminates a try-block begun by
5052
/// a code_push_catcht. At present the try block consists of the instructions
@@ -72,9 +74,6 @@ Date: December 2016
7274
/// instructions copy back to an ordinary local variable (or other expression)
7375
/// and set \#exception_value back to null, indicating the exception has been
7476
/// caught and normal control flow resumed.
75-
///
76-
/// Note that remove_exceptions introduces java_instanceof comparisons at
77-
/// present, so a remove_instanceof may be necessary after it completes.
7877
class remove_exceptionst
7978
{
8079
typedef std::vector<std::pair<
@@ -84,55 +83,62 @@ class remove_exceptionst
8483
public:
8584
explicit remove_exceptionst(
8685
symbol_tablet &_symbol_table,
87-
std::map<irep_idt, std::set<irep_idt>> &_exceptions_map):
88-
symbol_table(_symbol_table),
89-
exceptions_map(_exceptions_map)
86+
std::map<irep_idt, std::set<irep_idt>> &_exceptions_map,
87+
bool remove_added_instanceof)
88+
: symbol_table(_symbol_table),
89+
exceptions_map(_exceptions_map),
90+
remove_added_instanceof(remove_added_instanceof)
9091
{
9192
}
9293

93-
void operator()(
94-
goto_functionst &goto_functions);
94+
void operator()(goto_functionst &goto_functions);
9595

9696
protected:
9797
symbol_tablet &symbol_table;
9898
std::map<irep_idt, std::set<irep_idt>> &exceptions_map;
99+
bool remove_added_instanceof;
99100

100101
void add_exceptional_returns(
101-
const goto_functionst::function_mapt::iterator &);
102+
const irep_idt &function_id,
103+
goto_programt &goto_program);
102104

103105
void instrument_exception_handler(
104-
const goto_functionst::function_mapt::iterator &,
106+
const irep_idt &function_id,
107+
goto_programt &goto_program,
105108
const goto_programt::targett &);
106109

107110
void add_exception_dispatch_sequence(
108-
const goto_functionst::function_mapt::iterator &,
111+
const irep_idt &function_id,
112+
goto_programt &goto_program,
109113
const goto_programt::targett &instr_it,
110114
const stack_catcht &stack_catch,
111115
const std::vector<exprt> &locals);
112116

113117
void instrument_throw(
114-
const goto_functionst::function_mapt::iterator &,
118+
const irep_idt &function_id,
119+
goto_programt &goto_program,
115120
const goto_programt::targett &,
116121
const stack_catcht &,
117122
const std::vector<exprt> &);
118123

119124
void instrument_function_call(
120-
const goto_functionst::function_mapt::iterator &,
125+
const irep_idt &function_id,
126+
goto_programt &goto_program,
121127
const goto_programt::targett &,
122128
const stack_catcht &,
123129
const std::vector<exprt> &);
124130

125131
void instrument_exceptions(
126-
const goto_functionst::function_mapt::iterator &);
132+
const irep_idt &function_id,
133+
goto_programt &goto_program);
127134
};
128135

129136
/// adds exceptional return variables for every function that may escape
130137
/// exceptions
131138
void remove_exceptionst::add_exceptional_returns(
132-
const goto_functionst::function_mapt::iterator &func_it)
139+
const irep_idt &function_id,
140+
goto_programt &goto_program)
133141
{
134-
const irep_idt &function_id=func_it->first;
135-
goto_programt &goto_program=func_it->second.body;
136142

137143
auto maybe_symbol=symbol_table.lookup(function_id);
138144
INVARIANT(maybe_symbol, "functions should be recorded in the symbol table");
@@ -236,17 +242,17 @@ void remove_exceptionst::add_exceptional_returns(
236242
/// Translates an exception landing-pad into instructions that copy the
237243
/// in-flight exception pointer to a nominated expression, then clear the
238244
/// in-flight exception (i.e. null the pointer), hence marking it caught.
239-
/// \param func_it: iterator pointing to the function containing this
240-
/// landingpad instruction
241-
/// \param instr_it [in, out]: iterator pointing to the landingpad instruction.
245+
/// \param function_id: name of the function containing this landingpad
246+
/// instruction
247+
/// \param goto_program: body of the function containing this landingpad
248+
/// instruction
249+
/// \param instr_it: iterator pointing to the landingpad instruction.
242250
/// Will be overwritten.
243251
void remove_exceptionst::instrument_exception_handler(
244-
const goto_functionst::function_mapt::iterator &func_it,
252+
const irep_idt &function_id,
253+
goto_programt &goto_program,
245254
const goto_programt::targett &instr_it)
246255
{
247-
const irep_idt &function_id=func_it->first;
248-
goto_programt &goto_program=func_it->second.body;
249-
250256
PRECONDITION(instr_it->type==CATCH);
251257

252258
// retrieve the exception variable
@@ -285,20 +291,19 @@ void remove_exceptionst::instrument_exception_handler(
285291
/// if (exception instanceof ExnA) then goto handlerA
286292
/// else if (exception instanceof ExnB) then goto handlerB
287293
/// else goto universal_handler or (dead locals; function exit)
288-
/// \param func_it: iterator pointing to function instr_it belongs to
294+
/// \param function_id: name of the function to which instr_it belongs
295+
/// \param goto_program: body of the function to which instr_it belongs
289296
/// \param instr_it: throw or call instruction that may be an
290297
/// exception source
291298
/// \param stack_catch: exception handlers currently registered
292299
/// \param locals: local variables to kill on a function-exit edge
293300
void remove_exceptionst::add_exception_dispatch_sequence(
294-
const goto_functionst::function_mapt::iterator &func_it,
301+
const irep_idt &function_id,
302+
goto_programt &goto_program,
295303
const goto_programt::targett &instr_it,
296304
const remove_exceptionst::stack_catcht &stack_catch,
297305
const std::vector<exprt> &locals)
298306
{
299-
const irep_idt &function_id=func_it->first;
300-
goto_programt &goto_program=func_it->second.body;
301-
302307
// Unless we have a universal exception handler, jump to end of function
303308
// if not caught:
304309
goto_programt::targett default_target=goto_program.get_end_function();
@@ -343,6 +348,9 @@ void remove_exceptionst::add_exception_dispatch_sequence(
343348

344349
binary_predicate_exprt check(exc_thrown, ID_java_instanceof, expr);
345350
t_exc->guard=check;
351+
352+
if(remove_added_instanceof)
353+
remove_instanceof(t_exc, goto_program, symbol_table);
346354
}
347355
}
348356
}
@@ -360,10 +368,11 @@ void remove_exceptionst::add_exception_dispatch_sequence(
360368
}
361369
}
362370

363-
/// instruments each throw with conditional GOTOS to the corresponding
371+
/// instruments each throw with conditional GOTOS to the corresponding
364372
/// exception handlers
365373
void remove_exceptionst::instrument_throw(
366-
const goto_functionst::function_mapt::iterator &func_it,
374+
const irep_idt &function_id,
375+
goto_programt &goto_program,
367376
const goto_programt::targett &instr_it,
368377
const remove_exceptionst::stack_catcht &stack_catch,
369378
const std::vector<exprt> &locals)
@@ -383,11 +392,11 @@ void remove_exceptionst::instrument_throw(
383392
return;
384393

385394
add_exception_dispatch_sequence(
386-
func_it, instr_it, stack_catch, locals);
395+
function_id, goto_program, instr_it, stack_catch, locals);
387396

388397
// find the symbol where the thrown exception should be stored:
389-
const symbolt &exc_symbol=
390-
symbol_table.lookup_ref(id2string(func_it->first)+EXC_SUFFIX);
398+
const symbolt &exc_symbol =
399+
symbol_table.lookup_ref(id2string(function_id) + EXC_SUFFIX);
391400
symbol_exprt exc_thrown=exc_symbol.symbol_expr();
392401

393402
// add the assignment with the appropriate cast
@@ -401,16 +410,14 @@ void remove_exceptionst::instrument_throw(
401410
/// instruments each function call that may escape exceptions with conditional
402411
/// GOTOS to the corresponding exception handlers
403412
void remove_exceptionst::instrument_function_call(
404-
const goto_functionst::function_mapt::iterator &func_it,
413+
const irep_idt &function_id,
414+
goto_programt &goto_program,
405415
const goto_programt::targett &instr_it,
406416
const stack_catcht &stack_catch,
407417
const std::vector<exprt> &locals)
408418
{
409419
PRECONDITION(instr_it->type==FUNCTION_CALL);
410420

411-
goto_programt &goto_program=func_it->second.body;
412-
const irep_idt &function_id=func_it->first;
413-
414421
// save the address of the next instruction
415422
goto_programt::targett next_it=instr_it;
416423
next_it++;
@@ -430,7 +437,7 @@ void remove_exceptionst::instrument_function_call(
430437
if(callee_inflight_exception && local_inflight_exception)
431438
{
432439
add_exception_dispatch_sequence(
433-
func_it, instr_it, stack_catch, locals);
440+
function_id, goto_program, instr_it, stack_catch, locals);
434441

435442
const symbol_exprt callee_inflight_exception_expr=
436443
callee_inflight_exception->symbol_expr();
@@ -463,12 +470,12 @@ void remove_exceptionst::instrument_function_call(
463470
/// handlers. Additionally, it re-computes the live-range of local variables in
464471
/// order to add DEAD instructions.
465472
void remove_exceptionst::instrument_exceptions(
466-
const goto_functionst::function_mapt::iterator &func_it)
473+
const irep_idt &function_id,
474+
goto_programt &goto_program)
467475
{
468476
stack_catcht stack_catch; // stack of try-catch blocks
469477
std::vector<std::vector<exprt>> stack_locals; // stack of local vars
470478
std::vector<exprt> locals;
471-
goto_programt &goto_program=func_it->second.body;
472479

473480
if(goto_program.empty())
474481
return;
@@ -486,7 +493,7 @@ void remove_exceptionst::instrument_exceptions(
486493
// Is it an exception landing pad (start of a catch block)?
487494
if(statement==ID_exception_landingpad)
488495
{
489-
instrument_exception_handler(func_it, instr_it);
496+
instrument_exception_handler(function_id, goto_program, instr_it);
490497
}
491498
// Is it a catch handler pop?
492499
else if(statement==ID_pop_catch)
@@ -551,39 +558,43 @@ void remove_exceptionst::instrument_exceptions(
551558
}
552559
else if(instr_it->type==THROW)
553560
{
554-
instrument_throw(func_it, instr_it, stack_catch, locals);
561+
instrument_throw(
562+
function_id, goto_program, instr_it, stack_catch, locals);
555563
}
556564
else if(instr_it->type==FUNCTION_CALL)
557565
{
558-
instrument_function_call(func_it, instr_it, stack_catch, locals);
566+
instrument_function_call(
567+
function_id, goto_program, instr_it, stack_catch, locals);
559568
}
560569
}
561570
}
562571

563572
void remove_exceptionst::operator()(goto_functionst &goto_functions)
564573
{
565574
Forall_goto_functions(it, goto_functions)
566-
add_exceptional_returns(it);
575+
add_exceptional_returns(it->first, it->second.body);
567576
Forall_goto_functions(it, goto_functions)
568-
instrument_exceptions(it);
577+
instrument_exceptions(it->first, it->second.body);
569578
}
570579

571580
/// removes throws/CATCH-POP/CATCH-PUSH
572581
void remove_exceptions(
573582
symbol_tablet &symbol_table,
574-
goto_functionst &goto_functions)
583+
goto_functionst &goto_functions,
584+
remove_exceptions_typest type)
575585
{
576586
const namespacet ns(symbol_table);
577587
std::map<irep_idt, std::set<irep_idt>> exceptions_map;
578588
uncaught_exceptions(goto_functions, ns, exceptions_map);
579-
remove_exceptionst remove_exceptions(symbol_table, exceptions_map);
589+
remove_exceptionst remove_exceptions(
590+
symbol_table,
591+
exceptions_map,
592+
type == remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
580593
remove_exceptions(goto_functions);
581594
}
582595

583596
/// removes throws/CATCH-POP/CATCH-PUSH
584-
void remove_exceptions(goto_modelt &goto_model)
597+
void remove_exceptions(goto_modelt &goto_model, remove_exceptions_typest type)
585598
{
586-
remove_exceptions(
587-
goto_model.symbol_table,
588-
goto_model.goto_functions);
599+
remove_exceptions(goto_model.symbol_table, goto_model.goto_functions, type);
589600
}

src/goto-programs/remove_exceptions.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@ Date: December 2016
2121
// Removes 'throw x' and CATCH-PUSH/CATCH-POP
2222
// and adds the required instrumentation (GOTOs and assignments)
2323

24-
void remove_exceptions(symbol_tablet &, goto_functionst &);
25-
void remove_exceptions(goto_modelt &);
24+
enum class remove_exceptions_typest
25+
{
26+
REMOVE_ADDED_INSTANCEOF,
27+
DONT_REMOVE_INSTANCEOF,
28+
};
29+
30+
void remove_exceptions(
31+
goto_modelt &goto_model,
32+
remove_exceptions_typest type =
33+
remove_exceptions_typest::DONT_REMOVE_INSTANCEOF);
2634

2735
#endif

src/goto-programs/remove_instanceof.cpp

+26-5
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,17 @@ class remove_instanceoft
2828
class_hierarchy(symbol_table);
2929
}
3030

31-
// Lower instanceof for a single functions
31+
// Lower instanceof for a single function
3232
bool lower_instanceof(goto_programt &);
3333

34+
// Lower instanceof for a single instruction
35+
bool lower_instanceof(goto_programt &, goto_programt::targett);
36+
3437
protected:
3538
symbol_tablet &symbol_table;
3639
namespacet ns;
3740
class_hierarchyt class_hierarchy;
3841

39-
bool lower_instanceof(goto_programt &, goto_programt::targett);
40-
4142
std::size_t lower_instanceof(
4243
exprt &, goto_programt &, goto_programt::targett);
4344
};
@@ -168,9 +169,24 @@ bool remove_instanceoft::lower_instanceof(goto_programt &goto_program)
168169
}
169170

170171

172+
/// Replace an instanceof in the expression or guard of the passed instruction
173+
/// of the given function body with an explicit class-identifier test.
174+
/// \remarks Extra auxiliary variables may be introduced into symbol_table.
175+
/// \param target: The instruction to work on.
176+
/// \param goto_program: The function body containing the instruction.
177+
/// \param symbol_table: The symbol table to add symbols to.
178+
void remove_instanceof(
179+
goto_programt::targett target,
180+
goto_programt &goto_program,
181+
symbol_tablet &symbol_table)
182+
{
183+
remove_instanceoft rem(symbol_table);
184+
rem.lower_instanceof(goto_program, target);
185+
}
186+
171187
/// Replace every instanceof in the passed function with an explicit
172188
/// class-identifier test.
173-
/// Extra auxiliary variables may be introduced into symbol_table.
189+
/// \remarks Extra auxiliary variables may be introduced into symbol_table.
174190
/// \param function: The function to work on.
175191
/// \param symbol_table: The symbol table to add symbols to.
176192
void remove_instanceof(
@@ -183,7 +199,7 @@ void remove_instanceof(
183199

184200
/// Replace every instanceof in every function with an explicit
185201
/// class-identifier test.
186-
/// Extra auxiliary variables may be introduced into symbol_table.
202+
/// \remarks Extra auxiliary variables may be introduced into symbol_table.
187203
/// \param goto_functions: The functions to work on.
188204
/// \param symbol_table: The symbol table to add symbols to.
189205
void remove_instanceof(
@@ -198,6 +214,11 @@ void remove_instanceof(
198214
goto_functions.compute_location_numbers();
199215
}
200216

217+
/// Replace every instanceof in every function with an explicit
218+
/// class-identifier test.
219+
/// \remarks Extra auxiliary variables may be introduced into symbol_table.
220+
/// \param goto_model: The functions to work on and the symbol table to add
221+
/// symbols to.
201222
void remove_instanceof(goto_modelt &goto_model)
202223
{
203224
remove_instanceof(goto_model.goto_functions, goto_model.symbol_table);

src/goto-programs/remove_instanceof.h

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ Author: Chris Smowton, [email protected]
1616
#include "goto_functions.h"
1717
#include "goto_model.h"
1818

19+
void remove_instanceof(
20+
goto_programt::targett target,
21+
goto_programt &goto_program,
22+
symbol_tablet &symbol_table);
23+
1924
void remove_instanceof(
2025
goto_functionst::goto_functiont &function,
2126
symbol_tablet &symbol_table);

0 commit comments

Comments
 (0)