-
Notifications
You must be signed in to change notification settings - Fork 286
Expand file tree
/
Copy pathlazy_goto_model.h
More file actions
277 lines (246 loc) · 11.9 KB
/
lazy_goto_model.h
File metadata and controls
277 lines (246 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/// Author: Diffblue Ltd.
/// \file
/// Model for lazy loading of functions
#ifndef CPROVER_GOTO_PROGRAMS_LAZY_GOTO_MODEL_H
#define CPROVER_GOTO_PROGRAMS_LAZY_GOTO_MODEL_H
#include <langapi/language_file.h>
#include <goto-programs/abstract_goto_model.h>
#include <goto-programs/goto_model.h>
#include "lazy_goto_functions_map.h"
class optionst;
/// A GOTO model that produces function bodies on demand. It owns a
/// `language_filest`, which is used to populate symbol-table method bodies.
/// They are then passed through `goto_convert` and any driver-program-supplied
/// post-convert transformations to produce the final GOTO representation of the
/// desired function.
///
/// This can be converted to a conventional `goto_modelt` if desired by calling
/// `process_whole_model_and_freeze`.
///
/// The typical use case looks like:
///
/// lazy_goto_modelt model(...callback parameters...);
/// model.initialize(cmdline.args, options);
/// model.get_goto_function("needed_function1")
/// model.get_goto_function("needed_function2");
/// ...
/// model.get_goto_function("needed_functionN");
/// // optional:
/// std::unique_ptr<goto_modelt> concrete_model =
/// model.process_whole_model_and_freeze();
///
/// See the constructor `lazy_goto_modelt::lazy_goto_modelt` for more detail
/// on the callbacks needed.
class lazy_goto_modelt : public abstract_goto_modelt
{
public:
/// Callback function that post-processes a GOTO function. The
/// `goto_model_functiont` passed in has just been produced by `goto_convert`,
/// and so may contain function pointers, `RETURN` statements and other GOTO
/// constructs that are conventionally post-processed away.
/// The `model` parameter can be used to inspect other functions, but the
/// implementation should be aware that there may be GOTO functions that are
/// still to be converted, so it is not in its final state at this point.
typedef std::function<
void(goto_model_functiont &function, const abstract_goto_modelt &model)>
post_process_functiont;
/// Callback function that post-processes a whole GOTO model. The functions
/// in the model have been produced by `goto_convert` and then passed through
/// the corresponding `post_process_functiont`. Returns true on error,
/// in which case `lazy_goto_modelt::process_whole_model_and_freeze` will
/// return null.
typedef std::function<bool(goto_modelt &goto_model)> post_process_functionst;
/// Callback function that determines whether the creator of a
/// `lazy_goto_modelt` can itself supply a function body for a given name,
/// whether as a fallback or an override. Only used from
/// `can_produce_goto_function`, but should only return true for a function
/// that `generate_function_body` can actually provide a body for, otherwise
/// the `lazy_goto_modelt` user is likely to end up confused.
typedef lazy_goto_functions_mapt::can_generate_function_bodyt
can_generate_function_bodyt;
/// Callback function that may provide a body for a GOTO function, either as
/// a fallback (when we don't have source code for a function, often called a
/// stub function) or as an override (when we do have source code, but want to
/// e.g. replace a difficult-to-analyse function body with a simpler model,
/// or outright omission).
/// Gets parameters:
/// `function_name`: a symbol-table symbol name we're asked to populate
/// `symbol_table`: symbol table we should add new symbols to, such as
/// function local variables.
/// `function`: `goto_functiont` that we may populate. That could be done
/// directly, or by populating the corresponding symbol in the symbol table
/// and calling `goto_convert`.
/// `body_available`: true if we have source code for the function body, and
/// so the function will be given a body if this callback declines to
/// provide one. If you only want to provide fallback (stub) bodies, check
/// this is false before proceeding. If it is true and a body is supplied,
/// we are overriding the source code definition.
/// Returns: true if we provided a function body; false otherwise. When true
/// is returned our definition is definitive; when false is returned a body
/// will be generated from source code where available.
typedef lazy_goto_functions_mapt::generate_function_bodyt
generate_function_bodyt;
/// Construct a lazy GOTO model, supplying callbacks that customise its
/// behaviour. Consider using `from_handler_object` if the callbacks supplied
/// would be members of the same class (i.e.
/// `my_drivert::process_goto_function`,
/// `my_drivert::generate_function_body` etc). See the documentation of the
/// parameter types for more precise information on what a given callback
/// should do.
/// \param post_process_function: called to post-process a GOTO function after
/// it is `goto_convert`ed but before `get_goto_function` returns. This
/// usually runs transformations such as `remove_returns` and
/// `remove_virtual_functions`. It can be a no-op, in which case GOTO
/// programs will be returned exactly as produced by `goto_convert`.
/// \param post_process_functions: called to post-process the whole model
/// before `process_whole_model_and_freeze` returns. This usually runs
/// transformations that can only be applied once all functions to be
/// converted are known, such as dead global variable elimination.
/// \param driver_program_can_generate_function_body: boolean predicate to
/// indicate whether `driver_program_generate_function_body` can produce
/// a body for a given function name. If this returns true for a particular
/// function, so will `can_produce_function`.
/// \param driver_program_generate_function_body: called to give the driver
/// program the opportunity to provide a body for a function. It is passed
/// a boolean indicating whether a body is available conventionally (i.e.
/// generated from source code), so this hook can be used to provide
/// fallbacks for missing functions or to override available functions as
/// you like.
/// \param message_handler: used for logging.
explicit lazy_goto_modelt(
post_process_functiont post_process_function,
post_process_functionst post_process_functions,
can_generate_function_bodyt driver_program_can_generate_function_body,
generate_function_bodyt driver_program_generate_function_body,
message_handlert &message_handler);
lazy_goto_modelt(lazy_goto_modelt &&other);
lazy_goto_modelt &operator=(lazy_goto_modelt &&other)
{
goto_model = std::move(other.goto_model);
language_files = std::move(other.language_files);
return *this;
}
/// Create a lazy_goto_modelt from a object that defines function/module pass
/// handlers.
/// Its members functions will be used to construct the lazy model:
/// `post_process_function` gets `handler.process_goto_function`
/// `post_process_functions` gets `handler.process_goto_functions`
/// `driver_program_can_generate_function_body` gets
/// `handler.can_generate_function_body`
/// `driver_program_generate_function_body` gets
/// `handler.generate_function_body`
/// \param handler: An object that defines the handlers
/// \param options: The options passed to process_goto_functions
/// \param message_handler: The message_handler to use for logging
/// \tparam THandler: a type that defines methods process_goto_function and
/// process_goto_functions
template <typename THandler>
static lazy_goto_modelt from_handler_object(
THandler &handler,
const optionst &options,
message_handlert &message_handler)
{
return lazy_goto_modelt(
[&handler,
&options](goto_model_functiont &fun, const abstract_goto_modelt &model) {
handler.process_goto_function(fun, model, options);
},
[&handler, &options](goto_modelt &goto_model) -> bool {
return handler.process_goto_functions(goto_model, options);
},
[&handler](const irep_idt &name) -> bool {
return handler.can_generate_function_body(name);
},
[&handler](
const irep_idt &function_name,
symbol_table_baset &symbol_table,
goto_functiont &function,
bool is_first_chance) {
return handler.generate_function_body(
function_name, symbol_table, function, is_first_chance);
},
message_handler);
}
void
initialize(const std::vector<std::string> &files, const optionst &options);
/// Eagerly loads all functions from the symbol table.
void load_all_functions() const;
language_filet &add_language_file(const std::string &filename)
{
return language_files.add_file(filename);
}
/// The model returned here has access to the functions we've already
/// loaded but is frozen in the sense that, with regard to the facility to
/// load new functions, it has let it go.
/// Before freezing the functions all module-level passes are run
/// \param model: The lazy_goto_modelt to freeze
/// \return The frozen goto_modelt or an empty optional if freezing fails
static std::unique_ptr<goto_modelt>
process_whole_model_and_freeze(lazy_goto_modelt &&model)
{
if(model.finalize())
return nullptr;
return std::move(model.goto_model);
}
// Implement the abstract_goto_modelt interface:
/// Accessor to retrieve the internal goto_functionst.
/// Use with care; concurrent use of get_goto_function will have side-effects
/// on this map which may surprise users, including invalidating any iterators
/// they have stored.
const goto_functionst &get_goto_functions() const override
{
return goto_model->goto_functions;
}
const symbol_tablet &get_symbol_table() const override
{
return symbol_table;
}
bool can_produce_function(const irep_idt &id) const override;
/// Get a GOTO function body. `id` must be a valid symbol-table symbol. Its
/// body is produced by:
/// 1. If we already have a GOTO function body for `id`, return it.
/// 2. If the user's `driver_program_generate_function_body` function provides
/// a body, pass it through the user's `post_process_function` callback,
/// store and return it.
/// 3. If we already have a `codet` for the function stored in the symbol
/// table, `goto_convert` it, pass it through the user's
/// `post_process_function` callback, store it and return it.
/// 4. Otherwise, if some `languaget` claims to be able to produce it (this is
/// determined by `languaget::methods_provided`), call its
/// `languaget::convert_lazy_method` function. If that results in a `codet`
/// representation of the function stored in the symbol table, convert it
/// to GOTO and return it as in step (3).
const goto_functionst::goto_functiont &
get_goto_function(const irep_idt &id) override
{
return goto_functions.at(id);
}
/// Check that the goto model is well-formed
///
/// The validation mode indicates whether well-formedness check failures are
/// reported via DATA_INVARIANT violations or exceptions.
void validate(
const validation_modet vm = validation_modet::INVARIANT,
const goto_model_validation_optionst &goto_model_validation_options =
goto_model_validation_optionst{}) const override
{
goto_model->validate(vm, goto_model_validation_options);
}
private:
std::unique_ptr<goto_modelt> goto_model;
public:
/// Reference to symbol_table in the internal goto_model
symbol_tablet &symbol_table;
private:
const lazy_goto_functions_mapt goto_functions;
language_filest language_files;
// Function/module processing functions
const post_process_functiont post_process_function;
const post_process_functionst post_process_functions;
const can_generate_function_bodyt driver_program_can_generate_function_body;
const generate_function_bodyt driver_program_generate_function_body;
/// Logging helper field
message_handlert &message_handler;
bool finalize();
};
#endif // CPROVER_GOTO_PROGRAMS_LAZY_GOTO_MODEL_H