Skip to content

Commit 823782c

Browse files
authored
Merge pull request #5384 from martin-cs/refactor/split-up-histories
Move call_stack_history to own file
2 parents 2996579 + 2f4108d commit 823782c

File tree

6 files changed

+348
-316
lines changed

6 files changed

+348
-316
lines changed

src/analyses/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ SRC = ai.cpp \
33
ai_history.cpp \
44
call_graph.cpp \
55
call_graph_helpers.cpp \
6+
call_stack_history.cpp \
67
constant_propagator.cpp \
78
custom_bitvector_analysis.cpp \
89
dependence_graph.cpp \

src/analyses/ai_history.cpp

-202
Original file line numberDiff line numberDiff line change
@@ -27,205 +27,3 @@ xmlt ai_history_baset::output_xml(void) const
2727
xml.data = out.str();
2828
return xml;
2929
}
30-
31-
ai_history_baset::step_returnt
32-
call_stack_historyt::step(locationt to, const trace_sett &others) const
33-
{
34-
DATA_INVARIANT(current_stack != nullptr, "current_stack must exist");
35-
36-
cse_ptrt next_stack = nullptr;
37-
38-
// First construct what the new history would be.
39-
// This requires special handling if this edge is a function call or return
40-
if(current_stack->current_location->is_function_call())
41-
{
42-
locationt l_return = std::next(current_stack->current_location);
43-
44-
if(l_return->location_number == to->location_number)
45-
{
46-
// Is skipping the function call, only update the location
47-
next_stack = cse_ptrt(
48-
std::make_shared<call_stack_entryt>(l_return, current_stack->caller));
49-
}
50-
else
51-
{
52-
// An interprocedural (call) edge; add to the current stack
53-
54-
// If the recursion limit has been reached
55-
// shorten the stack / merge with the most recent invocation
56-
// before we extend
57-
cse_ptrt shorten = current_stack;
58-
59-
if(has_recursion_limit())
60-
{
61-
unsigned int number_of_recursive_calls = 0;
62-
cse_ptrt first_found = nullptr; // The most recent recursive call
63-
64-
// Iterate back through the call stack
65-
for(cse_ptrt i = current_stack->caller; i != nullptr; i = i->caller)
66-
{
67-
if(
68-
i->current_location->location_number ==
69-
current_stack->current_location->location_number)
70-
{
71-
// Found a recursive instance
72-
if(first_found == nullptr)
73-
{
74-
first_found = i;
75-
}
76-
++number_of_recursive_calls;
77-
if(number_of_recursive_calls == recursion_limit)
78-
{
79-
shorten = first_found;
80-
break;
81-
}
82-
}
83-
}
84-
}
85-
86-
next_stack = cse_ptrt(std::make_shared<call_stack_entryt>(to, shorten));
87-
}
88-
}
89-
else if(current_stack->current_location->is_end_function())
90-
{
91-
if(current_stack->caller == nullptr)
92-
{
93-
// Trying to return but there was no caller?
94-
// Refuse to do the transition outright
95-
return std::make_pair(ai_history_baset::step_statust::BLOCKED, nullptr);
96-
}
97-
else
98-
{
99-
// The expected call return site...
100-
locationt l_caller_return =
101-
std::next(current_stack->caller->current_location);
102-
103-
if(l_caller_return->location_number == to->location_number)
104-
{
105-
// ... which is where we are going
106-
next_stack = cse_ptrt(std::make_shared<call_stack_entryt>(
107-
to, current_stack->caller->caller));
108-
}
109-
else
110-
{
111-
// Not possible to return to somewhere other than the call site
112-
return std::make_pair(ai_history_baset::step_statust::BLOCKED, nullptr);
113-
}
114-
}
115-
}
116-
else
117-
{
118-
// Just update the location
119-
next_stack =
120-
cse_ptrt(std::make_shared<call_stack_entryt>(to, current_stack->caller));
121-
}
122-
INVARIANT(next_stack != nullptr, "All branches should initialise next_stack");
123-
124-
// Create the potential next history
125-
trace_ptrt next(new call_stack_historyt(next_stack, recursion_limit));
126-
// It would be nice to use make_shared here but ... that doesn't work with
127-
// protected constructors
128-
129-
// If there is already an equivalent history, merge with that instead
130-
auto it = others.find(next);
131-
132-
if(it == others.end())
133-
{
134-
return std::make_pair(ai_history_baset::step_statust::NEW, next);
135-
}
136-
else
137-
{
138-
return std::make_pair(ai_history_baset::step_statust::MERGED, *it);
139-
}
140-
}
141-
142-
bool call_stack_historyt::operator<(const ai_history_baset &op) const
143-
{
144-
auto other = dynamic_cast<const call_stack_historyt *>(&op);
145-
PRECONDITION(other != nullptr);
146-
147-
return *(this->current_stack) < *(other->current_stack);
148-
}
149-
150-
bool call_stack_historyt::operator==(const ai_history_baset &op) const
151-
{
152-
auto other = dynamic_cast<const call_stack_historyt *>(&op);
153-
PRECONDITION(other != nullptr);
154-
155-
return *(this->current_stack) == *(other->current_stack);
156-
}
157-
158-
void call_stack_historyt::output(std::ostream &out) const
159-
{
160-
out << "call_stack_history : stack "
161-
<< current_stack->current_location->location_number;
162-
cse_ptrt working = current_stack->caller;
163-
while(working != nullptr)
164-
{
165-
out << " from " << working->current_location->location_number;
166-
working = working->caller;
167-
}
168-
return;
169-
}
170-
171-
bool call_stack_historyt::call_stack_entryt::
172-
operator<(const call_stack_entryt &op) const
173-
{
174-
if(
175-
this->current_location->location_number <
176-
op.current_location->location_number)
177-
{
178-
return true;
179-
}
180-
else if(
181-
this->current_location->location_number >
182-
op.current_location->location_number)
183-
{
184-
return false;
185-
}
186-
else
187-
{
188-
INVARIANT(
189-
this->current_location->location_number ==
190-
op.current_location->location_number,
191-
"Implied by if-then-else");
192-
193-
if(this->caller == op.caller)
194-
{
195-
return false; // Because they are equal
196-
}
197-
else if(this->caller == nullptr)
198-
{
199-
return true; // Shorter stacks are 'lower'
200-
}
201-
else if(op.caller == nullptr)
202-
{
203-
return false;
204-
}
205-
else
206-
{
207-
// Sort by the rest of the stack
208-
return *(this->caller) < *(op.caller);
209-
}
210-
}
211-
UNREACHABLE;
212-
}
213-
214-
bool call_stack_historyt::call_stack_entryt::
215-
operator==(const call_stack_entryt &op) const
216-
{
217-
if(
218-
this->current_location->location_number ==
219-
op.current_location->location_number)
220-
{
221-
if(this->caller == op.caller)
222-
{
223-
return true;
224-
}
225-
else if(this->caller != nullptr && op.caller != nullptr)
226-
{
227-
return *(this->caller) == *(op.caller);
228-
}
229-
}
230-
return false;
231-
}

src/analyses/ai_history.h

-111
Original file line numberDiff line numberDiff line change
@@ -219,93 +219,6 @@ class ahistoricalt : public ai_history_baset
219219
}
220220
};
221221

222-
/// Records the call stack
223-
/// Care must be taken when using this on recursive code; it will need the
224-
/// domain to be capable of limiting the recursion.
225-
class call_stack_historyt : public ai_history_baset
226-
{
227-
protected:
228-
class call_stack_entryt;
229-
typedef std::shared_ptr<const call_stack_entryt> cse_ptrt;
230-
class call_stack_entryt
231-
{
232-
public:
233-
locationt current_location;
234-
cse_ptrt caller;
235-
236-
call_stack_entryt(locationt l, cse_ptrt p) : current_location(l), caller(p)
237-
{
238-
}
239-
240-
bool operator<(const call_stack_entryt &op) const;
241-
bool operator==(const call_stack_entryt &op) const;
242-
};
243-
244-
cse_ptrt current_stack;
245-
// DATA_INVARIANT(current_stack != nullptr, "current_stack must exist");
246-
// DATA_INVARIANT(current_stack->current.is_dereferenceable(),
247-
// "Must not be _::end()")
248-
249-
// At what point to merge with a previous call stack when handling recursion
250-
// Setting to 0 disables completely
251-
unsigned int recursion_limit;
252-
253-
bool has_recursion_limit(void) const
254-
{
255-
return recursion_limit != 0;
256-
}
257-
258-
call_stack_historyt(cse_ptrt cur_stack, unsigned int rec_lim)
259-
: ai_history_baset(cur_stack->current_location),
260-
current_stack(cur_stack),
261-
recursion_limit(rec_lim)
262-
{
263-
PRECONDITION(
264-
cur_stack != nullptr); // A little late by now but worth documenting
265-
}
266-
267-
public:
268-
explicit call_stack_historyt(locationt l)
269-
: ai_history_baset(l),
270-
current_stack(std::make_shared<call_stack_entryt>(l, nullptr)),
271-
recursion_limit(0)
272-
{
273-
}
274-
275-
call_stack_historyt(locationt l, unsigned int rec_lim)
276-
: ai_history_baset(l),
277-
current_stack(std::make_shared<call_stack_entryt>(l, nullptr)),
278-
recursion_limit(rec_lim)
279-
{
280-
}
281-
282-
call_stack_historyt(const call_stack_historyt &old)
283-
: ai_history_baset(old),
284-
current_stack(old.current_stack),
285-
recursion_limit(old.recursion_limit)
286-
{
287-
}
288-
289-
step_returnt step(locationt to, const trace_sett &others) const override;
290-
291-
bool operator<(const ai_history_baset &op) const override;
292-
bool operator==(const ai_history_baset &op) const override;
293-
294-
const locationt &current_location(void) const override
295-
{
296-
return current_stack->current_location;
297-
}
298-
299-
// Use default widening
300-
// Typically this would be used for loops, which are not tracked
301-
// it would be possible to use this to improve the handling of recursion
302-
bool should_widen(const ai_history_baset &other) const override
303-
{
304-
return ai_history_baset::should_widen(other);
305-
}
306-
307-
void output(std::ostream &out) const override;
308-
};
309222

310223
/// As more detailed histories can get complex (for example, nested loops
311224
/// or deep, mutually recursive call stacks) they often need some user
@@ -335,28 +248,4 @@ class ai_history_factory_default_constructort : public ai_history_factory_baset
335248
}
336249
};
337250

338-
// Allows passing a recursion limit
339-
class call_stack_history_factoryt : public ai_history_factory_baset
340-
{
341-
protected:
342-
unsigned int recursion_limit;
343-
344-
public:
345-
explicit call_stack_history_factoryt(unsigned int rec_lim)
346-
: recursion_limit(rec_lim)
347-
{
348-
}
349-
350-
ai_history_baset::trace_ptrt epoch(ai_history_baset::locationt l) override
351-
{
352-
ai_history_baset::trace_ptrt p(
353-
std::make_shared<call_stack_historyt>(l, recursion_limit));
354-
return p;
355-
}
356-
357-
virtual ~call_stack_history_factoryt()
358-
{
359-
}
360-
};
361-
362251
#endif // CPROVER_ANALYSES_AI_HISTORY_H

0 commit comments

Comments
 (0)