Skip to content

Commit a659bc0

Browse files
Add lazy_goto_functions_mapt
Add lazy_goto_functions_mapt, a lazily populated function map, and use it in lazy_goto_modelt Allow post-processing functions run on a function-by-function basis Update lazy_goto_modelt to run module passes
1 parent 7e1ecc9 commit a659bc0

File tree

5 files changed

+287
-24
lines changed

5 files changed

+287
-24
lines changed
+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
// Copyright 2016-2017 Diffblue Limited. All Rights Reserved.
2+
3+
/// \file
4+
/// A lazy wrapper for goto_functionst.
5+
6+
#ifndef CPROVER_GOTO_PROGRAMS_LAZY_GOTO_FUNCTIONS_MAP_H
7+
#define CPROVER_GOTO_PROGRAMS_LAZY_GOTO_FUNCTIONS_MAP_H
8+
9+
#include <unordered_set>
10+
#include "goto_functions.h"
11+
#include "goto_convert_functions.h"
12+
#include <util/message.h>
13+
#include <util/language_file.h>
14+
15+
16+
/// Provides a wrapper for a map of lazily loaded goto_functiont.
17+
/// This incrementally builds a goto-functions object, while permitting
18+
/// access to goto programs while they are still under construction.
19+
/// The intended workflow:
20+
/// 1. The front-end registers the functions that are potentially
21+
/// available, probably by use of util/language_files.h
22+
/// 2. The main function registers functions that should be run on
23+
/// each program, in sequence, after it is converted.
24+
/// 3. Analyses will then access functions using the `at` function
25+
/// \tparam bodyt: The type of the function bodies, usually goto_programt
26+
template<typename bodyt>
27+
class lazy_goto_functions_mapt final
28+
{
29+
public:
30+
// NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL
31+
typedef irep_idt key_type;
32+
// NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL
33+
typedef goto_function_templatet<bodyt> &mapped_type;
34+
/// The type of elements returned by const members
35+
// NOLINTNEXTLINE(readability/identifiers) - name matches mapped_type
36+
typedef const goto_function_templatet<bodyt> &const_mapped_type;
37+
// NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL
38+
typedef std::pair<const key_type, goto_function_templatet<bodyt>> value_type;
39+
// NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL
40+
typedef value_type &reference;
41+
// NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL
42+
typedef const value_type &const_reference;
43+
// NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL
44+
typedef value_type *pointer;
45+
// NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL
46+
typedef const value_type *const_pointer;
47+
// NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL
48+
typedef std::size_t size_type;
49+
50+
typedef
51+
std::function<void(goto_functionst::goto_functiont &function)>
52+
post_process_functiont;
53+
54+
private:
55+
typedef std::map<key_type, goto_function_templatet<bodyt>> underlying_mapt;
56+
underlying_mapt &goto_functions;
57+
/// Names of functions that are already fully available in the programt state.
58+
/// \remarks These functions do not need processing before being returned
59+
/// whenever they are requested
60+
mutable std::unordered_set<irep_idt, irep_id_hash> processed_functions;
61+
62+
language_filest &language_files;
63+
symbol_tablet &symbol_table;
64+
// This is mutable because it has internal state that it changes during the
65+
// course of conversion. Strictly it should make that state mutable or
66+
// recreate it for each conversion, but it's easier just to store it mutable.
67+
mutable goto_convert_functionst convert_functions;
68+
const post_process_functiont post_process_function;
69+
70+
public:
71+
/// Creates a lazy_goto_functions_mapt.
72+
lazy_goto_functions_mapt(
73+
underlying_mapt &goto_functions,
74+
language_filest &language_files,
75+
symbol_tablet &symbol_table,
76+
post_process_functiont post_process_function,
77+
message_handlert &message_handler)
78+
: goto_functions(goto_functions),
79+
language_files(language_files),
80+
symbol_table(symbol_table),
81+
convert_functions(symbol_table, message_handler),
82+
post_process_function(std::move(post_process_function))
83+
{
84+
}
85+
86+
/// Gets the number of functions in the map.
87+
/// \return The number of functions in the map.
88+
size_type size() const
89+
{
90+
return language_files.lazy_method_map.size();
91+
}
92+
93+
/// Returns whether the map contains any mappings.
94+
/// \return Whether the map contains any mappings.
95+
bool empty() const { return language_files.lazy_method_map.empty(); }
96+
97+
/// Checks whether a given function exists in the map.
98+
/// \param name: The name of the function to search for.
99+
/// \return True if the map contains the given function.
100+
bool contains(const key_type &name) const
101+
{
102+
return language_files.lazy_method_map.count(name)!=0;
103+
}
104+
105+
/// Gets the body for a given function.
106+
/// \param name: The name of the function to search for.
107+
/// \return The function body corresponding to the given function.
108+
const_mapped_type at(const key_type &name) const
109+
{
110+
return ensure_function_loaded_internal(name).second;
111+
}
112+
113+
/// Gets the body for a given function.
114+
/// \param name: The name of the function to search for.
115+
/// \return The function body corresponding to the given function.
116+
mapped_type at(const key_type &name)
117+
{
118+
return ensure_function_loaded_internal(name).second;
119+
}
120+
121+
void unload(const key_type &name) const { goto_functions.erase(name); }
122+
123+
private:
124+
// This returns a non-const reference, but if you use this method from a
125+
// const method then you should not return such a reference without making it
126+
// const first
127+
reference ensure_function_loaded_internal(const key_type &name) const
128+
{
129+
reference named_function=ensure_entry_converted(name);
130+
mapped_type function=named_function.second;
131+
if(processed_functions.count(name)==0)
132+
{
133+
// Run function-pass conversions
134+
post_process_function(function);
135+
// Assign procedure-local location numbers for now
136+
function.body.compute_location_numbers();
137+
processed_functions.insert(name);
138+
}
139+
return named_function;
140+
}
141+
142+
reference ensure_entry_converted(const key_type &name) const
143+
{
144+
typename underlying_mapt::iterator it=goto_functions.find(name);
145+
if(it!=goto_functions.end())
146+
return *it;
147+
if(symbol_table.lookup_ref(name).value.is_nil())
148+
{
149+
// Fill in symbol table entry body
150+
// If this returns false then it's a stub
151+
language_files.convert_lazy_method(name, symbol_table);
152+
}
153+
// Create goto_functiont
154+
goto_functionst::goto_functiont function;
155+
convert_functions.convert_function(name, function);
156+
// Add to map
157+
return *goto_functions.emplace(name, std::move(function)).first;
158+
}
159+
};
160+
161+
#endif // CPROVER_GOTO_PROGRAMS_LAZY_GOTO_FUNCTIONS_MAP_H

src/goto-programs/lazy_goto_model.cpp

+38-8
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,24 @@
1616

1717
#include <fstream>
1818

19-
lazy_goto_modelt::lazy_goto_modelt(message_handlert &message_handler)
19+
//! @cond Doxygen_suppress_Lambda_in_initializer_list
20+
lazy_goto_modelt::lazy_goto_modelt(
21+
post_process_functiont post_process_function,
22+
post_process_functionst post_process_functions,
23+
message_handlert &message_handler)
2024
: goto_model(new goto_modelt()),
2125
symbol_table(goto_model->symbol_table),
22-
goto_functions(goto_model->goto_functions),
26+
goto_functions(
27+
goto_model->goto_functions.function_map,
28+
language_files,
29+
symbol_table,
30+
[this] (goto_functionst::goto_functiont &function) -> void
31+
{
32+
this->post_process_function(function, symbol_table);
33+
},
34+
message_handler),
35+
post_process_function(std::move(post_process_function)),
36+
post_process_functions(std::move(post_process_functions)),
2337
message_handler(message_handler)
2438
{
2539
language_files.set_message_handler(message_handler);
@@ -28,11 +42,22 @@ lazy_goto_modelt::lazy_goto_modelt(message_handlert &message_handler)
2842
lazy_goto_modelt::lazy_goto_modelt(lazy_goto_modelt &&other)
2943
: goto_model(std::move(other.goto_model)),
3044
symbol_table(goto_model->symbol_table),
31-
goto_functions(goto_model->goto_functions),
45+
goto_functions(
46+
goto_model->goto_functions.function_map,
47+
language_files,
48+
symbol_table,
49+
[this] (goto_functionst::goto_functiont &function) -> void
50+
{
51+
this->post_process_function(function, symbol_table);
52+
},
53+
other.message_handler),
3254
language_files(std::move(other.language_files)),
55+
post_process_function(std::move(other.post_process_function)),
56+
post_process_functions(std::move(other.post_process_functions)),
3357
message_handler(other.message_handler)
3458
{
3559
}
60+
//! @endcond
3661

3762
void lazy_goto_modelt::initialize(const cmdlinet &cmdline)
3863
{
@@ -115,15 +140,12 @@ void lazy_goto_modelt::initialize(const cmdlinet &cmdline)
115140
}
116141
}
117142

118-
for(const auto &file : binaries)
143+
for(const std::string &file : binaries)
119144
{
120145
msg.status() << "Reading GOTO program from file" << messaget::eom;
121146

122-
if(read_object_and_link(
123-
file, symbol_table, goto_functions, message_handler))
124-
{
147+
if(read_object_and_link(file, *goto_model, message_handler))
125148
throw 0;
126-
}
127149
}
128150

129151
bool binaries_provided_start =
@@ -177,3 +199,11 @@ void lazy_goto_modelt::load_all_functions() const
177199
{
178200
goto_convert(*goto_model, message_handler);
179201
}
202+
203+
204+
bool lazy_goto_modelt::finalize()
205+
{
206+
language_files.clear();
207+
208+
return post_process_functions(*goto_model);
209+
}

src/goto-programs/lazy_goto_model.h

+50-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,26 @@
99
#include <util/language_file.h>
1010

1111
#include "goto_model.h"
12+
#include "lazy_goto_functions_map.h"
1213
#include "goto_convert_functions.h"
1314

1415
class cmdlinet;
16+
class optionst;
1517

1618

1719
/// Model that holds partially loaded map of functions
1820
class lazy_goto_modelt
1921
{
2022
public:
21-
explicit lazy_goto_modelt(message_handlert &message_handler);
23+
typedef std::function<void(
24+
goto_functionst::goto_functiont &function,
25+
symbol_tablet &symbol_table)> post_process_functiont;
26+
typedef std::function<bool(goto_modelt &goto_model)> post_process_functionst;
27+
28+
explicit lazy_goto_modelt(
29+
post_process_functiont post_process_function,
30+
post_process_functionst post_process_functions,
31+
message_handlert &message_handler);
2232

2333
lazy_goto_modelt(lazy_goto_modelt &&other);
2434

@@ -29,6 +39,33 @@ class lazy_goto_modelt
2939
return *this;
3040
}
3141

42+
/// Create a lazy_goto_modelt from a object that defines function/module pass
43+
/// handlers
44+
/// \param handler: An object that defines the handlers
45+
/// \param options: The options passed to process_goto_functions
46+
/// \param message_handler: The message_handler to use for logging
47+
/// \tparam THandler a type that defines methods process_goto_function and
48+
/// process_goto_functions
49+
template<typename THandler>
50+
static lazy_goto_modelt from_handler_object(
51+
THandler &handler,
52+
const optionst &options,
53+
message_handlert &message_handler)
54+
{
55+
return lazy_goto_modelt(
56+
[&handler] (
57+
goto_functionst::goto_functiont &function,
58+
symbol_tablet &symbol_table) -> void
59+
{
60+
handler.process_goto_function(function, symbol_table);
61+
},
62+
[&handler, &options] (goto_modelt &goto_model) -> bool
63+
{
64+
return handler.process_goto_functions(goto_model, options);
65+
},
66+
message_handler);
67+
}
68+
3269
void initialize(const cmdlinet &cmdline);
3370

3471
/// Eagerly loads all functions from the symbol table.
@@ -37,10 +74,14 @@ class lazy_goto_modelt
3774
/// The model returned here has access to the functions we've already
3875
/// loaded but is frozen in the sense that, with regard to the facility to
3976
/// load new functions, it has let it go.
77+
/// Before freezing the functions all module-level passes are run
4078
/// \param model: The lazy_goto_modelt to freeze
4179
/// \returns The frozen goto_modelt or an empty optional if freezing fails
42-
static std::unique_ptr<goto_modelt> freeze(lazy_goto_modelt &&model)
80+
static std::unique_ptr<goto_modelt> process_whole_model_and_freeze(
81+
lazy_goto_modelt &&model)
4382
{
83+
if(model.finalize())
84+
return nullptr;
4485
return std::move(model.goto_model);
4586
}
4687

@@ -50,13 +91,19 @@ class lazy_goto_modelt
5091
public:
5192
/// Reference to symbol_table in the internal goto_model
5293
symbol_tablet &symbol_table;
53-
goto_functionst &goto_functions;
94+
const lazy_goto_functions_mapt<goto_programt> goto_functions;
5495

5596
private:
5697
language_filest language_files;
5798

99+
// Function/module processing functions
100+
const post_process_functiont post_process_function;
101+
const post_process_functionst post_process_functions;
102+
58103
/// Logging helper field
59104
message_handlert &message_handler;
105+
106+
bool finalize();
60107
};
61108

62109
#endif // CPROVER_GOTO_PROGRAMS_LAZY_GOTO_MODEL_H

0 commit comments

Comments
 (0)