Skip to content

Commit ada033c

Browse files
authoredMar 19, 2018
Merge pull request #3 from chrisr-diffblue/sharing-map-structs
Use sharing_mapt instead of std::map in full_struct_abstract_object

File tree

4 files changed

+180
-54
lines changed

4 files changed

+180
-54
lines changed
 

‎src/analyses/variable-sensitivity/abstract_object.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include <goto-programs/goto_program.h>
3737
#include <util/expr.h>
38+
#include <util/sharing_map.h>
3839

3940
class typet;
4041
class constant_exprt;
@@ -116,7 +117,12 @@ class abstract_objectt:public std::enable_shared_from_this<abstract_objectt>
116117
std::ostream &out, const class ai_baset &ai, const namespacet &ns) const;
117118

118119
typedef std::set<goto_programt::const_targett> locationst;
119-
120+
typedef sharing_mapt<irep_idt, abstract_object_pointert, irep_id_hash>
121+
shared_mapt;
122+
123+
static void dump_map(std::ostream out, const shared_mapt &m);
124+
static void dump_map_diff(
125+
std::ostream out, const shared_mapt &m1, const shared_mapt &m2);
120126

121127
abstract_object_pointert clone() const
122128
{
@@ -194,7 +200,6 @@ class abstract_objectt:public std::enable_shared_from_this<abstract_objectt>
194200
const abstract_object_visitort &visitor) const
195201
{ return shared_from_this(); }
196202

197-
198203
private:
199204
// To enforce copy-on-write these are private and have read-only accessors
200205
typet t;
@@ -238,6 +243,15 @@ class abstract_objectt:public std::enable_shared_from_this<abstract_objectt>
238243
const std::map<keyt, abstract_object_pointert> &map2,
239244
std::map<keyt, abstract_object_pointert> &out_map);
240245

246+
247+
template<class keyt>
248+
static bool merge_shared_maps(
249+
const sharing_mapt<keyt, abstract_object_pointert, irep_id_hash> &map1,
250+
const sharing_mapt<keyt, abstract_object_pointert, irep_id_hash> &map2,
251+
sharing_mapt<keyt, abstract_object_pointert, irep_id_hash> &out_map);
252+
253+
254+
241255
// The one exception is merge in descendant classes, which needs this
242256
void make_top() { top=true; this->make_top_internal(); }
243257
void clear_top() { top=false; this->clear_top_internal(); }
@@ -288,5 +302,34 @@ bool abstract_objectt::merge_maps(
288302
return modified;
289303
}
290304

305+
template<typename keyt>
306+
bool abstract_objectt::merge_shared_maps(
307+
const sharing_mapt<keyt, abstract_object_pointert, irep_id_hash> &m1,
308+
const sharing_mapt<keyt, abstract_object_pointert, irep_id_hash> &m2,
309+
sharing_mapt<keyt, abstract_object_pointert, irep_id_hash> &out_map)
310+
{
311+
typedef sharing_mapt<irep_idt, abstract_object_pointert,
312+
irep_id_hash>
313+
abstract_object_mapt;
314+
315+
bool modified=false;
316+
317+
abstract_object_mapt::delta_viewt delta_view;
318+
m1.get_delta_view(m2, delta_view, true);
319+
320+
for(auto &item : delta_view)
321+
{
322+
bool changes = false;
323+
abstract_object_pointert v_new = abstract_objectt::merge(
324+
item.m, item.other_m, changes);
325+
if (changes)
326+
{
327+
modified = true;
328+
out_map[item.k] = v_new;
329+
}
330+
}
331+
332+
return modified;
333+
}
291334

292335
#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_OBJECT_H

‎src/analyses/variable-sensitivity/abstract_value.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,44 @@ abstract_valuet::abstract_valuet(
7171
const namespacet &ns):
7272
abstract_objectt(expr, environment, ns)
7373
{}
74+
75+
76+
void abstract_objectt::dump_map(
77+
std::ostream out, const abstract_objectt::shared_mapt &m)
78+
{
79+
shared_mapt::viewt view;
80+
m.get_view(view);
81+
82+
out << "{";
83+
bool first=true;
84+
for(auto &item : view)
85+
{
86+
out << (first ? "" : ", ") << item.first;
87+
first = false;
88+
}
89+
out << "}";
90+
}
91+
92+
/**
93+
* \brief Dump all elements in m1 that are different or missing in m2
94+
*
95+
* \param m1 the 'target' sharing_map
96+
* \param m2 the reference sharing map
97+
*/
98+
void abstract_objectt::dump_map_diff(
99+
std::ostream out,
100+
const abstract_objectt::shared_mapt &m1,
101+
const abstract_objectt::shared_mapt &m2)
102+
{
103+
shared_mapt::delta_viewt delta_view;
104+
m1.get_delta_view(m2, delta_view, false);
105+
106+
out << "DELTA{";
107+
bool first = true;
108+
for(auto &item : delta_view)
109+
{
110+
out << (first ? "" : ", ") << item.k << "=" << item.in_both;
111+
first = false;
112+
}
113+
out << "}";
114+
}

‎src/analyses/variable-sensitivity/full_struct_abstract_object.cpp

Lines changed: 87 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ Author: Thomas Kiley, thomas.kiley@diffblue.com
2020
#include <iostream>
2121
#endif
2222

23+
/**
24+
* \brief Explicit copy-constructor to make it clear that the shared_map
25+
* used to store the values of fields is copy-constructed as well
26+
* to ensure it shares as much data as possible.
27+
*/
28+
full_struct_abstract_objectt::full_struct_abstract_objectt(
29+
const full_struct_abstract_objectt &ao):
30+
struct_abstract_objectt(ao), map(ao.map)
31+
{
32+
DATA_INVARIANT(verify(), "Structural invariants maintained");
33+
}
34+
2335
/*******************************************************************\
2436
2537
Function: full_struct_abstract_objectt::struct_abstract_objectt
@@ -124,13 +136,13 @@ abstract_object_pointert full_struct_abstract_objectt::read_component(
124136
{
125137
PRECONDITION(!is_bottom());
126138

127-
irep_idt c=member_expr.get_component_name();
139+
const irep_idt c=member_expr.get_component_name();
128140

129-
struct_mapt::const_iterator it=map.find(c);
141+
shared_struct_mapt::const_find_type value=map.find(c);
130142

131-
if(it!=map.cend())
143+
if(value.second)
132144
{
133-
return it->second;
145+
return value.first;
134146
}
135147
else
136148
{
@@ -182,29 +194,31 @@ sharing_ptrt<struct_abstract_objectt>
182194
member_expr.compound().type(), false, true));
183195
}
184196

185-
internal_sharing_ptrt<full_struct_abstract_objectt> copy(
186-
new full_struct_abstract_objectt(*this));
197+
const auto &result=
198+
std::dynamic_pointer_cast<full_struct_abstract_objectt>(mutable_clone());
187199

188200
if(!stack.empty())
189201
{
190202
abstract_object_pointert starting_value;
191-
irep_idt c=member_expr.get_component_name();
192-
if(map.find(c)==map.cend())
203+
const irep_idt c=member_expr.get_component_name();
204+
shared_struct_mapt::const_find_type old_value = map.find(c);
205+
if(!old_value.second)
193206
{
194207
starting_value=
195208
environment.abstract_object_factory(
196209
member_expr.type(), ns, true, false);
197210
}
198211
else
199212
{
200-
starting_value=map.at(c);
213+
starting_value=old_value.first;
201214
}
202215

203-
copy->map[c]=
216+
result->map[c] =
204217
environment.write(starting_value, value, stack, ns, merging_write);
205-
copy->clear_top();
206-
DATA_INVARIANT(copy->verify(), "Structural invariants maintained");;
207-
return copy;
218+
219+
result->clear_top();
220+
DATA_INVARIANT(result->verify(), "Structural invariants maintained");
221+
return result;
208222
}
209223
else
210224
{
@@ -213,41 +227,40 @@ sharing_ptrt<struct_abstract_objectt>
213227
std::cout << "Setting component" << std::endl;
214228
#endif
215229

216-
irep_idt c=member_expr.get_component_name();
230+
const irep_idt c=member_expr.get_component_name();
217231

218232
if(merging_write)
219233
{
220234
if(is_top()) // struct is top
221235
{
222-
DATA_INVARIANT(copy->verify(), "Structural invariants maintained");;
223-
return copy;
236+
DATA_INVARIANT(result->verify(), "Structural invariants maintained");
237+
return result;
224238
}
225239

226-
INVARIANT(!copy->map.empty(), "If not top, map cannot be empty");
240+
INVARIANT(!result->map.empty(), "If not top, map cannot be empty");
227241

228-
struct_mapt &m=copy->map;
242+
shared_struct_mapt::const_find_type old_value=result->map.find(c);
229243

230-
struct_mapt::iterator it=m.find(c);
231-
232-
if(it==m.end()) // component is top
244+
if(!old_value.second) // component is top
233245
{
234-
DATA_INVARIANT(copy->verify(), "Structural invariants maintained");;
235-
return copy;
246+
DATA_INVARIANT(result->verify(), "Structural invariants maintained");
247+
return result;
236248
}
237249

238250
bool dummy;
239251

240-
it->second=abstract_objectt::merge(it->second, value, dummy);
252+
result->map[c] = abstract_objectt::merge(old_value.first, value, dummy);
241253
}
242254
else
243255
{
244-
copy->map[c]=value;
245-
copy->clear_top();
246-
INVARIANT(!copy->is_bottom(), "top != bottom");
256+
result->map[c] = value;
257+
result->clear_top();
258+
INVARIANT(!result->is_bottom(), "top != bottom");
247259
}
248260

249-
DATA_INVARIANT(copy->verify(), "Structural invariants maintained");;
250-
return copy;
261+
DATA_INVARIANT(result->verify(), "Structural invariants maintained");
262+
263+
return result;
251264
}
252265
}
253266

@@ -272,15 +285,27 @@ Function: full_struct_abstract_objectt::output
272285
void full_struct_abstract_objectt::output(
273286
std::ostream &out, const ai_baset &ai, const namespacet &ns) const
274287
{
288+
// To ensure that a consistent ordering of fields is output, use
289+
// the underlying type declaration for this struct to determine
290+
// the ordering
291+
struct_union_typet type_decl = to_struct_union_type(ns.follow(type()));
292+
293+
bool first = true;
294+
275295
out << "{";
276-
for(const auto &entry : map)
296+
for(const auto field : type_decl.components())
277297
{
278-
if(entry.first!=map.cbegin()->first)
298+
auto value = map.find(field.get_name());
299+
if(value.second)
279300
{
280-
out << ", ";
301+
if(!first)
302+
{
303+
out << ", ";
304+
}
305+
out << '.' << field.get_name() << '=';
306+
value.first->output(out, ai, ns);
307+
first = false;
281308
}
282-
out << "." << entry.first << "=";
283-
entry.second->output(out, ai, ns);
284309
}
285310
out << "}";
286311
}
@@ -362,22 +387,19 @@ abstract_object_pointert full_struct_abstract_objectt::merge_constant_structs(
362387
}
363388
else
364389
{
365-
struct_mapt merged_map;
366-
bool modified=
367-
abstract_objectt::merge_maps<irep_idt>(map, other->map, merged_map);
390+
const auto &result=
391+
std::dynamic_pointer_cast<full_struct_abstract_objectt>(mutable_clone());
392+
393+
bool modified = abstract_objectt::merge_shared_maps<irep_idt>(
394+
map, other->map, result->map);
395+
368396
if(!modified)
369397
{
370398
DATA_INVARIANT(verify(), "Structural invariants maintained");
371399
return shared_from_this();
372400
}
373401
else
374402
{
375-
const auto &result=
376-
std::dynamic_pointer_cast<full_struct_abstract_objectt>(
377-
mutable_clone());
378-
379-
result->map=merged_map;
380-
381403
INVARIANT(!result->is_top(), "Merge of maps will not generate top");
382404
INVARIANT(!result->is_bottom(), "Merge of maps will not generate bottom");
383405
DATA_INVARIANT(result->verify(), "Structural invariants maintained");
@@ -397,18 +419,33 @@ abstract_object_pointert full_struct_abstract_objectt::merge_constant_structs(
397419
* \return A new abstract_object if it's contents is modifed, or this if
398420
* no modification is needed
399421
*/
400-
abstract_object_pointert
401-
full_struct_abstract_objectt::visit_sub_elements(
422+
abstract_object_pointert full_struct_abstract_objectt::visit_sub_elements(
402423
const abstract_object_visitort &visitor) const
403424
{
404425
const auto &result=
405-
std::dynamic_pointer_cast<full_struct_abstract_objectt>(
406-
mutable_clone());
426+
std::dynamic_pointer_cast<full_struct_abstract_objectt>(mutable_clone());
427+
428+
bool modified = false;
429+
430+
shared_struct_mapt::viewt view;
431+
result->map.get_view(view);
407432

408-
for(auto &item : result->map)
433+
for(auto &item : view)
409434
{
410-
item.second=visitor.visit(item.second);
435+
auto newval = visitor.visit(item.second);
436+
if(newval != item.second)
437+
{
438+
result->map[item.first] = visitor.visit(item.second);
439+
modified = true;
440+
}
411441
}
412442

413-
return result;
443+
if(modified)
444+
{
445+
return result;
446+
}
447+
else
448+
{
449+
return shared_from_this();
450+
}
414451
}

‎src/analyses/variable-sensitivity/full_struct_abstract_object.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Thomas Kiley, thomas.kiley@diffblue.com
1313
#include <iosfwd>
1414
#include <analyses/variable-sensitivity/abstract_object.h>
1515
#include <analyses/variable-sensitivity/struct_abstract_object.h>
16+
#include <util/sharing_map.h>
1617

1718
class abstract_environmentt;
1819
class member_exprt;
@@ -22,6 +23,9 @@ class full_struct_abstract_objectt:public struct_abstract_objectt
2223
public:
2324
typedef sharing_ptrt<full_struct_abstract_objectt> constant_struct_pointert;
2425

26+
// Define an explicit copy constructor to ensure sharing of maps
27+
full_struct_abstract_objectt(const full_struct_abstract_objectt &ao);
28+
2529
explicit full_struct_abstract_objectt(const typet &type);
2630

2731
full_struct_abstract_objectt(const typet &type, bool top, bool bottom);
@@ -41,8 +45,9 @@ class full_struct_abstract_objectt:public struct_abstract_objectt
4145

4246
private:
4347
// no entry means component is top
44-
typedef std::map<irep_idt, abstract_object_pointert> struct_mapt;
45-
struct_mapt map;
48+
typedef sharing_mapt<irep_idt, abstract_object_pointert, irep_id_hash>
49+
shared_struct_mapt;
50+
shared_struct_mapt map;
4651

4752
abstract_object_pointert merge_constant_structs(
4853
constant_struct_pointert other) const;

0 commit comments

Comments
 (0)
Please sign in to comment.