Skip to content

Commit c078858

Browse files
Introduce lazy_goto_modelt
Introduces a class that holds a goto_modelt and language_filest to allow for lazy loading of functions. Don't eagerly convert functions during initialisation of lazy_goto_modelt. Instead adds a function to allow eager loading at a later stage if required (it always is at the moment).
1 parent a22dd1c commit c078858

9 files changed

+326
-57
lines changed

src/goto-programs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ SRC = basic_blocks.cpp \
2727
interpreter.cpp \
2828
interpreter_evaluate.cpp \
2929
json_goto_trace.cpp \
30+
lazy_goto_model.cpp \
3031
link_goto_model.cpp \
3132
link_to_library.cpp \
3233
loop_ids.cpp \

src/goto-programs/goto_functions_template.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ class goto_functions_templatet
121121
return *this;
122122
}
123123

124+
void unload(const irep_idt &name) { function_map.erase(name); }
125+
124126
void clear()
125127
{
126128
function_map.clear();

src/goto-programs/initialize_goto_model.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,9 @@ goto_modelt initialize_goto_model(
132132
// Rebuild the entry-point, using the language annotation of the
133133
// existing __CPROVER_start function:
134134
rebuild_goto_start_functiont rebuild_existing_start(
135-
msg.get_message_handler(),
136135
cmdline,
137-
goto_model.symbol_table,
138-
goto_model.goto_functions);
136+
goto_model,
137+
msg.get_message_handler());
139138
entry_point_generation_failed=rebuild_existing_start();
140139
}
141140
else if(!binaries_provided_start)

src/goto-programs/lazy_goto_model.cpp

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Copyright 2017 Diffblue Limited. All Rights Reserved.
2+
3+
/// \file
4+
/// Model for lazy loading of functions
5+
6+
#include "lazy_goto_model.h"
7+
#include "read_goto_binary.h"
8+
#include "rebuild_goto_start_function.h"
9+
10+
#include <langapi/mode.h>
11+
12+
#include <util/cmdline.h>
13+
#include <util/config.h>
14+
#include <util/language.h>
15+
#include <util/unicode.h>
16+
17+
#include <fstream>
18+
19+
lazy_goto_modelt::lazy_goto_modelt(message_handlert &message_handler)
20+
: goto_model(new goto_modelt()),
21+
symbol_table(goto_model->symbol_table),
22+
goto_functions(goto_model->goto_functions),
23+
message_handler(message_handler)
24+
{
25+
language_files.set_message_handler(message_handler);
26+
}
27+
28+
lazy_goto_modelt::lazy_goto_modelt(lazy_goto_modelt &&other)
29+
: goto_model(std::move(other.goto_model)),
30+
symbol_table(goto_model->symbol_table),
31+
goto_functions(goto_model->goto_functions),
32+
language_files(std::move(other.language_files)),
33+
message_handler(other.message_handler)
34+
{
35+
}
36+
37+
void lazy_goto_modelt::initialize(const cmdlinet &cmdline)
38+
{
39+
messaget msg(message_handler);
40+
41+
const std::vector<std::string> &files=cmdline.args;
42+
if(files.empty())
43+
{
44+
msg.error() << "Please provide a program" << messaget::eom;
45+
throw 0;
46+
}
47+
48+
std::vector<std::string> binaries, sources;
49+
binaries.reserve(files.size());
50+
sources.reserve(files.size());
51+
52+
for(const auto &file : files)
53+
{
54+
if(is_goto_binary(file))
55+
binaries.push_back(file);
56+
else
57+
sources.push_back(file);
58+
}
59+
60+
if(!sources.empty())
61+
{
62+
for(const auto &filename : sources)
63+
{
64+
#ifdef _MSC_VER
65+
std::ifstream infile(widen(filename));
66+
#else
67+
std::ifstream infile(filename);
68+
#endif
69+
70+
if(!infile)
71+
{
72+
msg.error() << "failed to open input file `" << filename
73+
<< '\'' << messaget::eom;
74+
throw 0;
75+
}
76+
77+
std::pair<language_filest::file_mapt::iterator, bool> result =
78+
language_files.file_map.emplace(filename, language_filet());
79+
80+
language_filet &lf=result.first->second;
81+
82+
lf.filename=filename;
83+
lf.language=get_language_from_filename(filename);
84+
85+
if(lf.language==nullptr)
86+
{
87+
source_locationt location;
88+
location.set_file(filename);
89+
msg.error().source_location=location;
90+
msg.error() << "failed to figure out type of file" << messaget::eom;
91+
throw 0;
92+
}
93+
94+
languaget &language=*lf.language;
95+
language.set_message_handler(message_handler);
96+
language.get_language_options(cmdline);
97+
98+
msg.status() << "Parsing " << filename << messaget::eom;
99+
100+
if(language.parse(infile, filename))
101+
{
102+
msg.error() << "PARSING ERROR" << messaget::eom;
103+
throw 0;
104+
}
105+
106+
lf.get_modules();
107+
}
108+
109+
msg.status() << "Converting" << messaget::eom;
110+
111+
if(language_files.typecheck(symbol_table))
112+
{
113+
msg.error() << "CONVERSION ERROR" << messaget::eom;
114+
throw 0;
115+
}
116+
}
117+
118+
for(const auto &file : binaries)
119+
{
120+
msg.status() << "Reading GOTO program from file" << messaget::eom;
121+
122+
if(read_object_and_link(
123+
file, symbol_table, goto_functions, message_handler))
124+
{
125+
throw 0;
126+
}
127+
}
128+
129+
bool binaries_provided_start =
130+
symbol_table.has_symbol(goto_functionst::entry_point());
131+
132+
bool entry_point_generation_failed=false;
133+
134+
if(binaries_provided_start && cmdline.isset("function"))
135+
{
136+
// Rebuild the entry-point, using the language annotation of the
137+
// existing __CPROVER_start function:
138+
rebuild_lazy_goto_start_functiont rebuild_existing_start(
139+
cmdline, *this, message_handler);
140+
entry_point_generation_failed=rebuild_existing_start();
141+
}
142+
else if(!binaries_provided_start)
143+
{
144+
// Unsure of the rationale for only generating stubs when there are no
145+
// GOTO binaries in play; simply mirroring old code in language_uit here.
146+
if(binaries.empty())
147+
{
148+
// Enable/disable stub generation for opaque methods
149+
bool stubs_enabled=cmdline.isset("generate-opaque-stubs");
150+
language_files.set_should_generate_opaque_method_stubs(stubs_enabled);
151+
}
152+
153+
// Allow all language front-ends to try to provide the user-specified
154+
// (--function) entry-point, or some language-specific default:
155+
entry_point_generation_failed=
156+
language_files.generate_support_functions(symbol_table);
157+
}
158+
159+
if(entry_point_generation_failed)
160+
{
161+
msg.error() << "SUPPORT FUNCTION GENERATION ERROR" << messaget::eom;
162+
throw 0;
163+
}
164+
165+
if(language_files.final(symbol_table))
166+
{
167+
msg.error() << "FINAL STAGE CONVERSION ERROR" << messaget::eom;
168+
throw 0;
169+
}
170+
171+
// stupid hack
172+
config.set_object_bits_from_symbol_table(symbol_table);
173+
}
174+
175+
/// Eagerly loads all functions from the symbol table.
176+
void lazy_goto_modelt::load_all_functions() const
177+
{
178+
goto_convert(*goto_model, message_handler);
179+
}

src/goto-programs/lazy_goto_model.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2016-2017 Diffblue Limited. All Rights Reserved.
2+
3+
/// \file
4+
/// Model for lazy loading of functions
5+
6+
#ifndef CPROVER_GOTO_PROGRAMS_LAZY_GOTO_MODEL_H
7+
#define CPROVER_GOTO_PROGRAMS_LAZY_GOTO_MODEL_H
8+
9+
#include <util/language_file.h>
10+
11+
#include "goto_model.h"
12+
#include "goto_convert_functions.h"
13+
14+
class cmdlinet;
15+
16+
17+
/// Model that holds partially loaded map of functions
18+
class lazy_goto_modelt
19+
{
20+
public:
21+
explicit lazy_goto_modelt(message_handlert &message_handler);
22+
23+
lazy_goto_modelt(lazy_goto_modelt &&other);
24+
25+
lazy_goto_modelt &operator=(lazy_goto_modelt &&other)
26+
{
27+
goto_model = std::move(other.goto_model);
28+
language_files = std::move(other.language_files);
29+
return *this;
30+
}
31+
32+
void initialize(const cmdlinet &cmdline);
33+
34+
/// Eagerly loads all functions from the symbol table.
35+
void load_all_functions() const;
36+
37+
/// The model returned here has access to the functions we've already
38+
/// loaded but is frozen in the sense that, with regard to the facility to
39+
/// load new functions, it has let it go.
40+
/// \param model: The lazy_goto_modelt to freeze
41+
/// \returns The frozen goto_modelt or an empty optional if freezing fails
42+
static std::unique_ptr<goto_modelt> freeze(lazy_goto_modelt &&model)
43+
{
44+
return std::move(model.goto_model);
45+
}
46+
47+
private:
48+
std::unique_ptr<goto_modelt> goto_model;
49+
50+
public:
51+
/// Reference to symbol_table in the internal goto_model
52+
symbol_tablet &symbol_table;
53+
goto_functionst &goto_functions;
54+
55+
private:
56+
language_filest language_files;
57+
58+
/// Logging helper field
59+
message_handlert &message_handler;
60+
};
61+
62+
#endif // CPROVER_GOTO_PROGRAMS_LAZY_GOTO_MODEL_H

src/goto-programs/rebuild_goto_start_function.cpp

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
#include "rebuild_goto_start_function.h"
1010

11-
#include <goto-programs/goto_functions.h>
1211
#include <util/language.h>
1312
#include <util/symbol.h>
1413
#include <util/symbol_table.h>
@@ -17,22 +16,21 @@
1716
#include <langapi/mode.h>
1817
#include <memory>
1918

20-
/// To rebuild the _start funciton in the event the program was compiled into
19+
/// To rebuild the _start function in the event the program was compiled into
2120
/// GOTO with a different entry function selected.
21+
/// \param goto_model: The goto functions (to replace the body of the _start
22+
/// function) and symbol table (to replace the _start function symbol) of the
23+
/// program.
2224
/// \param _message_handler: The message handler to report any messages with
23-
/// \param symbol_table: The symbol table of the program (to replace the _start
24-
/// functions symbo)
25-
/// \param goto_functions: The goto functions of the program (to replace the
26-
/// body of the _start function).
27-
rebuild_goto_start_functiont::rebuild_goto_start_functiont(
28-
message_handlert &_message_handler,
25+
template<typename goto_modelt>
26+
rebuild_goto_start_function_baset<goto_modelt>::
27+
rebuild_goto_start_function_baset(
2928
const cmdlinet &cmdline,
30-
symbol_tablet &symbol_table,
31-
goto_functionst &goto_functions):
32-
messaget(_message_handler),
29+
goto_modelt &goto_model,
30+
message_handlert &message_handler):
31+
messaget(message_handler),
3332
cmdline(cmdline),
34-
symbol_table(symbol_table),
35-
goto_functions(goto_functions)
33+
goto_model(goto_model)
3634
{
3735
}
3836

@@ -44,7 +42,8 @@ rebuild_goto_start_functiont::rebuild_goto_start_functiont(
4442
/// called from _start
4543
/// \return Returns true if either the symbol is not found, or something went
4644
/// wrong with generating the start_function. False otherwise.
47-
bool rebuild_goto_start_functiont::operator()()
45+
template<typename goto_modelt>
46+
bool rebuild_goto_start_function_baset<goto_modelt>::operator()()
4847
{
4948
const irep_idt &mode=get_entry_point_mode();
5049

@@ -58,43 +57,40 @@ bool rebuild_goto_start_functiont::operator()()
5857
remove_existing_entry_point();
5958

6059
bool return_code=
61-
language->generate_support_functions(symbol_table);
60+
language->generate_support_functions(goto_model.symbol_table);
6261

63-
// Remove the function from the goto_functions so it is copied back in
62+
// Remove the function from the goto functions so it is copied back in
6463
// from the symbol table during goto_convert
6564
if(!return_code)
66-
{
67-
const auto &start_function=
68-
goto_functions.function_map.find(goto_functionst::entry_point());
69-
if(start_function!=goto_functions.function_map.end())
70-
{
71-
goto_functions.function_map.erase(start_function);
72-
}
73-
}
65+
goto_model.goto_functions.unload(goto_functionst::entry_point());
7466

7567
return return_code;
7668
}
7769

7870
/// Find out the mode of the current entry point to determine the mode of the
7971
/// replacement entry point
8072
/// \return A mode string saying which language to use
81-
irep_idt rebuild_goto_start_functiont::get_entry_point_mode() const
73+
template<typename goto_modelt>
74+
irep_idt
75+
rebuild_goto_start_function_baset<goto_modelt>::get_entry_point_mode() const
8276
{
8377
const symbolt &current_entry_point=
84-
*symbol_table.lookup(goto_functionst::entry_point());
78+
*goto_model.symbol_table.lookup(goto_functionst::entry_point());
8579
return current_entry_point.mode;
8680
}
8781

8882
/// Eliminate the existing entry point function symbol and any symbols created
8983
/// in that scope from the symbol table.
90-
void rebuild_goto_start_functiont::remove_existing_entry_point()
84+
template<typename goto_modelt>
85+
void
86+
rebuild_goto_start_function_baset<goto_modelt>::remove_existing_entry_point()
9187
{
9288
// Remove the function itself
93-
symbol_table.remove(goto_functionst::entry_point());
89+
goto_model.symbol_table.remove(goto_functionst::entry_point());
9490

9591
// And any symbols created in the scope of the entry point
9692
std::vector<irep_idt> entry_point_symbols;
97-
for(const auto &symbol_entry : symbol_table.symbols)
93+
for(const auto &symbol_entry : goto_model.symbol_table.symbols)
9894
{
9995
const bool is_entry_point_symbol=
10096
has_prefix(
@@ -107,6 +103,9 @@ void rebuild_goto_start_functiont::remove_existing_entry_point()
107103

108104
for(const irep_idt &entry_point_symbol : entry_point_symbols)
109105
{
110-
symbol_table.remove(entry_point_symbol);
106+
goto_model.symbol_table.remove(entry_point_symbol);
111107
}
112108
}
109+
110+
template class rebuild_goto_start_function_baset<goto_modelt>;
111+
template class rebuild_goto_start_function_baset<lazy_goto_modelt>;

0 commit comments

Comments
 (0)