Skip to content

Commit 5d2919b

Browse files
Interpreter: switch to sparse vector memory map
This will allow large address reservations for unbounded-sized objects, with actual cells allocated on demand. Original patch: From: Chris Smowton <[email protected]> Date: Tue, 21 Mar 2017 15:24:03 +0000 Subject: [PATCH 1/3] Interpreter: switch to sparse vector memory map
1 parent 2e62c66 commit 5d2919b

File tree

3 files changed

+176
-55
lines changed

3 files changed

+176
-55
lines changed

src/goto-programs/interpreter.cpp

+23-38
Original file line numberDiff line numberDiff line change
@@ -712,22 +712,24 @@ exprt interpretert::get_value(
712712
if(rhs[offset]<memory.size())
713713
{
714714
// We want the symbol pointed to
715-
memory_cellt &cell=memory[integer2unsigned(rhs[offset])];
716-
const typet type=get_type(cell.identifier);
715+
std::size_t address=integer2size_t(rhs[offset]);
716+
irep_idt identifier=address_to_identifier(address);
717+
size_t offset=address_to_offset(address);
718+
const typet type=get_type(identifier);
717719
exprt symbol_expr(ID_symbol, type);
718-
symbol_expr.set(ID_identifier, cell.identifier);
720+
symbol_expr.set(ID_identifier, identifier);
719721

720-
if(cell.offset==0)
722+
if(offset==0)
721723
return address_of_exprt(symbol_expr);
722724
if(ns.follow(type).id()==ID_struct)
723725
{
724-
irep_idt member_id=get_component_id(cell.identifier, cell.offset);
726+
irep_idt member_id=get_component_id(identifier, offset);
725727
member_exprt member_expr(symbol_expr, member_id);
726728
return address_of_exprt(member_expr);
727729
}
728730
index_exprt index_expr(
729731
symbol_expr,
730-
from_integer(cell.offset, integer_typet()));
732+
from_integer(offset, integer_typet()));
731733
return index_expr;
732734
}
733735

@@ -828,12 +830,13 @@ void interpretert::assign(
828830
{
829831
if((address+i)<memory.size())
830832
{
831-
memory_cellt &cell=memory[integer2unsigned(address+i)];
833+
std::size_t address_val=integer2size_t(address+i);
834+
memory_cellt &cell=memory[address_val];
832835
if(show)
833836
{
834837
status() << total_steps << " ** assigning "
835-
<< cell.identifier << "["
836-
<< cell.offset << "]:=" << rhs[i]
838+
<< address_to_identifier(address_val) << "["
839+
<< address_to_offset(address_val) << "]:=" << rhs[i]
837840
<< "\n" << eom;
838841
}
839842
cell.value=rhs[i];
@@ -913,8 +916,9 @@ void interpretert::execute_function_call()
913916
// Retrieve the empty last trace step struct we pushed for this step
914917
// of the interpreter run to fill it with the corresponding data
915918
goto_trace_stept &trace_step=steps.get_last_step();
916-
const memory_cellt &cell=memory[integer2size_t(a)];
917-
const irep_idt &identifier=cell.identifier;
919+
std::size_t address=integer2size_t(a);
920+
const memory_cellt &cell=memory[address];
921+
const irep_idt &identifier=address_to_identifier(address);
918922
trace_step.identifier=identifier;
919923

920924
const goto_functionst::function_mapt::const_iterator f_it=
@@ -1020,9 +1024,7 @@ void interpretert::build_memory_map()
10201024
{
10211025
// put in a dummy for NULL
10221026
memory.resize(1);
1023-
memory[0].offset=0;
1024-
memory[0].identifier="NULL-OBJECT";
1025-
memory[0].initialized=0;
1027+
inverse_memory_map[0]="NULL-OBJECT";
10261028

10271029
num_dynamic_objects=0;
10281030
dynamic_types.clear();
@@ -1062,18 +1064,10 @@ void interpretert::build_memory_map(const symbolt &symbol)
10621064

10631065
if(size!=0)
10641066
{
1065-
unsigned address=memory.size();
1067+
std::size_t address=memory.size();
10661068
memory.resize(address+size);
10671069
memory_map[symbol.name]=address;
1068-
1069-
for(size_t i=0; i<size; i++)
1070-
{
1071-
memory_cellt &cell=memory[address+i];
1072-
cell.identifier=symbol.name;
1073-
cell.offset=i;
1074-
cell.value=0;
1075-
cell.initialized=0;
1076-
}
1070+
inverse_memory_map[address]=symbol.name;
10771071
}
10781072
}
10791073

@@ -1136,12 +1130,10 @@ mp_integer interpretert::build_memory_map(
11361130

11371131
if(it!=dynamic_types.end())
11381132
{
1139-
unsigned offset=1;
1140-
unsigned address=memory_map[id];
1141-
while(memory[address+offset].offset>0) offset++;
1142-
1133+
std::size_t address=memory_map[id];
1134+
std::size_t current_size=base_address_to_alloc_size(address);
11431135
// current size <= size already recorded
1144-
if(size<=offset)
1136+
if(size<=current_size)
11451137
return memory_map[id];
11461138
}
11471139

@@ -1151,19 +1143,12 @@ mp_integer interpretert::build_memory_map(
11511143
if(size==0)
11521144
size=1; // This is a hack to create existence
11531145

1154-
unsigned address=memory.size();
1146+
std::size_t address=memory.size();
11551147
memory.resize(address+size);
11561148
memory_map[id]=address;
1149+
inverse_memory_map[address]=id;
11571150
dynamic_types.insert(std::pair<const irep_idt, typet>(id, alloc_type));
11581151

1159-
for(size_t i=0; i<size; i++)
1160-
{
1161-
memory_cellt &cell=memory[address+i];
1162-
cell.identifier=id;
1163-
cell.offset=i;
1164-
cell.value=0;
1165-
cell.initialized=0;
1166-
}
11671152
return address;
11681153
}
11691154

src/goto-programs/interpreter_class.h

+65-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212
#include <stack>
1313

1414
#include <util/arith_tools.h>
15+
#include <util/sparse_vector.h>
1516

1617
#include "goto_functions.h"
1718
#include "goto_trace.h"
@@ -68,6 +69,9 @@ class interpretert:public messaget
6869
// List of dynamically allocated symbols that are not in the symbol table
6970
typedef std::map<irep_idt, typet> dynamic_typest;
7071

72+
typedef std::map<irep_idt, function_assignmentst> output_valuest;
73+
output_valuest output_values;
74+
7175
// An assignment list annotated with the calling context.
7276
struct function_assignments_contextt
7377
{
@@ -103,27 +107,78 @@ class interpretert:public messaget
103107

104108
const goto_functionst &goto_functions;
105109

106-
typedef std::unordered_map<irep_idt, unsigned, irep_id_hash> memory_mapt;
110+
typedef std::unordered_map<irep_idt, std::size_t, irep_id_hash> memory_mapt;
111+
typedef std::map<std::size_t, irep_idt> inverse_memory_mapt;
107112
memory_mapt memory_map;
113+
inverse_memory_mapt inverse_memory_map;
114+
115+
const inverse_memory_mapt::value_type &address_to_object_record(
116+
std::size_t address) const
117+
{
118+
auto lower_bound=inverse_memory_map.lower_bound(address);
119+
if(lower_bound->first!=address)
120+
{
121+
assert(lower_bound!=inverse_memory_map.begin());
122+
--lower_bound;
123+
}
124+
return *lower_bound;
125+
}
126+
127+
irep_idt address_to_identifier(std::size_t address) const
128+
{
129+
return address_to_object_record(address).second;
130+
}
131+
132+
std::size_t address_to_offset(std::size_t address) const
133+
{
134+
return address-(address_to_object_record(address).first);
135+
}
136+
137+
std::size_t base_address_to_alloc_size(std::size_t address) const
138+
{
139+
assert(address_to_offset(address)==0);
140+
auto upper_bound=inverse_memory_map.upper_bound(address);
141+
std::size_t next_alloc_address=
142+
upper_bound==inverse_memory_map.end() ?
143+
memory.size() :
144+
upper_bound->first;
145+
return next_alloc_address-address;
146+
}
147+
148+
std::size_t base_address_to_actual_size(std::size_t address) const
149+
{
150+
auto memory_iter=memory.find(address);
151+
if(memory_iter==memory.end())
152+
return 0;
153+
std::size_t ret=0;
154+
std::size_t alloc_size=base_address_to_alloc_size(address);
155+
while(memory_iter!=memory.end() && ret<alloc_size)
156+
{
157+
++ret;
158+
++memory_iter;
159+
}
160+
return ret;
161+
}
108162

109163
class memory_cellt
110164
{
111165
public:
112-
irep_idt identifier;
113-
unsigned offset;
166+
memory_cellt() :
167+
value(0),
168+
initialized(0)
169+
{}
114170
mp_integer value;
115171
// Initialized is annotated even during reads
116172
// Set to 1 when written-before-read, -1 when read-before-written
117173
mutable char initialized;
118174
};
119175

120-
typedef std::vector<memory_cellt> memoryt;
176+
typedef sparse_vectort<memory_cellt> memoryt;
121177
typedef std::map<std::string, const irep_idt &> parameter_sett;
122178
// mapping <structure, field> -> value
123179
typedef std::pair<const irep_idt, const irep_idt> struct_member_idt;
124180
typedef std::map<struct_member_idt, const exprt> struct_valuest;
125181

126-
127182
// The memory is being annotated/reshaped even during reads
128183
// (ie to find a read-before-write location) thus memory
129184
// properties need to be mutable to avoid making all calls nonconst
@@ -135,6 +190,7 @@ class interpretert:public messaget
135190
void build_memory_map(const symbolt &symbol);
136191
mp_integer build_memory_map(const irep_idt &id, const typet &type);
137192
typet concretize_type(const typet &type);
193+
bool unbounded_size(const typet &);
138194
size_t get_size(const typet &type);
139195

140196
irep_idt get_component_id(const irep_idt &object, unsigned offset);
@@ -169,6 +225,10 @@ class interpretert:public messaget
169225
mp_integer address,
170226
mp_vectort &dest) const;
171227

228+
void read_unbounded(
229+
mp_integer address,
230+
mp_vectort &dest) const;
231+
172232
virtual void command();
173233

174234
class stack_framet

0 commit comments

Comments
 (0)