Skip to content

Commit 5c03a0a

Browse files
authored
Merge pull request #20306 from rjmccall/projection-formal-accesses
Always manage subobject projections with formal-access cleanups
2 parents 03c2ff4 + 7da688d commit 5c03a0a

23 files changed

+157
-107
lines changed

include/swift/Basic/DiverseStack.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define SWIFT_BASIC_DIVERSESTACK_H
2424

2525
#include "swift/Basic/Malloc.h"
26+
#include "llvm/ADT/SmallVector.h"
2627
#include "llvm/Support/PointerLikeTypeTraits.h"
2728
#include <cassert>
2829
#include <cstring>
@@ -293,6 +294,15 @@ template <class T> class DiverseStackImpl : private DiverseStackBase {
293294
return stable_iterator(End - it.Ptr);
294295
}
295296

297+
T &findAndAdvance(stable_iterator &i) {
298+
auto unstable_i = find(i);
299+
assert(unstable_i != end());
300+
T &value = *unstable_i;
301+
++unstable_i;
302+
i = stabilize(unstable_i);
303+
return value;
304+
}
305+
296306
class const_iterator {
297307
const char *Ptr;
298308
friend class DiverseStackImpl;
@@ -377,6 +387,22 @@ template <class T> class DiverseStackImpl : private DiverseStackBase {
377387
}
378388
};
379389

390+
/// A helper class for copying value off a DiverseStack.
391+
template <class T>
392+
class DiverseValueBuffer {
393+
llvm::SmallVector<char, sizeof(T) + 10 * sizeof(void*)> data;
394+
395+
public:
396+
DiverseValueBuffer(const T &value) {
397+
size_t size = value.allocated_size();
398+
data.reserve(size);
399+
data.set_size(size);
400+
memcpy(data.data(), reinterpret_cast<const void *>(&value), size);
401+
}
402+
403+
T &getCopy() { return *reinterpret_cast<T *>(data.data()); }
404+
};
405+
380406
} // end namespace swift
381407

382408
/// Allow stable_iterators to be put in things like TinyPtrVectors.

lib/SILGen/Cleanup.cpp

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,24 +53,6 @@ static bool hasAnyActiveCleanups(DiverseStackImpl<Cleanup>::iterator begin,
5353
return false;
5454
}
5555

56-
namespace {
57-
/// A CleanupBuffer is a location to which to temporarily copy a
58-
/// cleanup.
59-
class CleanupBuffer {
60-
SmallVector<char, sizeof(Cleanup) + 10 * sizeof(void *)> data;
61-
62-
public:
63-
CleanupBuffer(const Cleanup &cleanup) {
64-
size_t size = cleanup.allocated_size();
65-
data.reserve(size);
66-
data.set_size(size);
67-
memcpy(data.data(), reinterpret_cast<const void *>(&cleanup), size);
68-
}
69-
70-
Cleanup &getCopy() { return *reinterpret_cast<Cleanup *>(data.data()); }
71-
};
72-
} // end anonymous namespace
73-
7456
void CleanupManager::popTopDeadCleanups() {
7557
auto end = (innermostScope ? innermostScope->depth : stack.stable_end());
7658
assert(end.isValid());
@@ -83,6 +65,8 @@ void CleanupManager::popTopDeadCleanups() {
8365
}
8466
}
8567

68+
using CleanupBuffer = DiverseValueBuffer<Cleanup>;
69+
8670
void CleanupManager::popAndEmitCleanup(CleanupHandle handle,
8771
CleanupLocation loc,
8872
ForUnwind_t forUnwind) {
@@ -107,22 +91,30 @@ void CleanupManager::emitCleanups(CleanupsDepth depth, CleanupLocation loc,
10791
auto topOfStack = cur;
10892
#endif
10993
while (cur != depth) {
94+
// Advance the iterator.
95+
auto cleanupHandle = cur;
96+
auto iter = stack.find(cleanupHandle);
97+
Cleanup &stackCleanup = *iter;
98+
cur = stack.stabilize(++iter);
99+
110100
// Copy the cleanup off the stack if it needs to be emitted.
111101
// This is necessary both because we might need to pop the cleanup and
112102
// because the cleanup might push other cleanups that will invalidate
113103
// references onto the stack.
114-
auto iter = stack.find(cur);
115-
Cleanup &stackCleanup = *iter;
116104
Optional<CleanupBuffer> copiedCleanup;
117105
if (stackCleanup.isActive() && SGF.B.hasValidInsertionPoint()) {
118106
copiedCleanup.emplace(stackCleanup);
119107
}
120108

121-
// Advance the iterator.
122-
cur = stack.stabilize(++iter);
123-
124109
// Pop now if that was requested.
125110
if (popCleanups) {
111+
#ifndef NDEBUG
112+
// This is an implicit deactivation.
113+
if (stackCleanup.isActive()) {
114+
SGF.FormalEvalContext.checkCleanupDeactivation(cleanupHandle);
115+
}
116+
#endif
117+
126118
stack.pop();
127119

128120
#ifndef NDEBUG

lib/SILGen/Cleanup.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ class LLVM_LIBRARY_VISIBILITY CleanupManager {
165165
return *stack.find(iter);
166166
}
167167

168+
Cleanup &findAndAdvance(CleanupsDepth &iter) {
169+
return stack.findAndAdvance(iter);
170+
}
171+
168172
/// \brief Emit a branch to the given jump destination,
169173
/// threading out through any cleanups we need to run. This does not pop the
170174
/// cleanup stack.

lib/SILGen/FormalEvaluation.cpp

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -106,25 +106,28 @@ void FormalEvaluationScope::popImpl() {
106106
"popping formal-evaluation scopes out of order");
107107
context.innermostScope = previous;
108108

109-
// Check to see if there is anything going on here.
110-
111-
using iterator = FormalEvaluationContext::iterator;
112-
using stable_iterator = FormalEvaluationContext::stable_iterator;
109+
auto endDepth = *savedDepth;
113110

114-
iterator unwrappedSavedDepth = context.find(savedDepth.getValue());
115-
iterator iter = context.begin();
116-
if (iter == unwrappedSavedDepth)
111+
// Check to see if there is anything going on here.
112+
if (endDepth == context.stable_begin())
117113
return;
118114

115+
#ifndef NDEBUG
116+
// Verify that all the accesses are valid.
117+
for (auto i = context.begin(), e = context.find(endDepth); i != e; ++i) {
118+
i->verify(SGF);
119+
}
120+
#endif
121+
119122
// Save our start point to make sure that we are not adding any new cleanups
120123
// to the front of the stack.
121-
stable_iterator originalBegin = context.stable_begin();
122-
(void)originalBegin;
124+
auto originalBegin = context.stable_begin();
123125

124126
// Then working down the stack until we visit unwrappedSavedDepth...
125-
for (; iter != unwrappedSavedDepth; ++iter) {
126-
// Grab the next evaluation...
127-
FormalAccess &access = *iter;
127+
auto i = originalBegin;
128+
do {
129+
// Grab the next evaluation.
130+
FormalAccess &access = context.findAndAdvance(i);
128131

129132
// If this access was already finished, continue. This can happen if an
130133
// owned formal access was forwarded.
@@ -149,10 +152,9 @@ void FormalEvaluationScope::popImpl() {
149152
// code. We do a simple N^2 comparison here to detect this because it is
150153
// extremely unlikely more than a few writebacks are active at once.
151154
if (access.getKind() == FormalAccess::Exclusive) {
152-
iterator j = iter;
153-
++j;
154-
155-
for (; j != unwrappedSavedDepth; ++j) {
155+
// Note that we already advanced 'iter' above, so we can just start
156+
// iterating from there. Also, this doesn't invalidate the iterators.
157+
for (auto j = context.find(i), je = context.find(endDepth); j != je; ++j){
156158
FormalAccess &other = *j;
157159
if (other.getKind() != FormalAccess::Exclusive)
158160
continue;
@@ -167,33 +169,25 @@ void FormalEvaluationScope::popImpl() {
167169
//
168170
// This evaluates arbitrary code, so it's best to be paranoid
169171
// about iterators on the context.
170-
access.finish(SGF);
171-
}
172+
DiverseValueBuffer<FormalAccess> copiedAccess(access);
173+
copiedAccess.getCopy().finish(SGF);
174+
175+
} while (i != endDepth);
172176

173177
// Then check that we did not add any additional cleanups to the beginning of
174178
// the stack...
175179
assert(originalBegin == context.stable_begin() &&
176-
"more formal eval cleanups placed onto context during formal eval scope pop?!");
180+
"pushed more formal evaluations while popping formal evaluations?!");
177181

178182
// And then pop off all stack elements until we reach the savedDepth.
179-
context.pop(savedDepth.getValue());
183+
context.pop(endDepth);
180184
}
181185

182186
void FormalEvaluationScope::verify() const {
183-
// Check to see if there is anything going on here.
187+
// Walk up the stack to the saved depth.
184188
auto &context = SGF.FormalEvalContext;
185-
using iterator = FormalEvaluationContext::iterator;
186-
187-
iterator unwrappedSavedDepth = context.find(savedDepth.getValue());
188-
iterator iter = context.begin();
189-
if (iter == unwrappedSavedDepth)
190-
return;
191-
192-
// Then working down the stack until we visit unwrappedSavedDepth...
193-
for (; iter != unwrappedSavedDepth; ++iter) {
194-
// Grab the next evaluation verify that we can successfully access this
195-
// formal access.
196-
(*iter).verify(SGF);
189+
for (auto i = context.begin(), e = context.find(*savedDepth); i != e; ++i) {
190+
i->verify(SGF);
197191
}
198192
}
199193

lib/SILGen/FormalEvaluation.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ class FormalEvaluationContext {
139139
stable_iterator stable_begin() { return stabilize(begin()); }
140140
iterator find(stable_iterator iter) { return stack.find(iter); }
141141

142+
FormalAccess &findAndAdvance(stable_iterator &stable) {
143+
return stack.findAndAdvance(stable);
144+
}
145+
142146
template <class U, class... ArgTypes> void push(ArgTypes &&... args) {
143147
stack.push<U>(std::forward<ArgTypes>(args)...);
144148
}
@@ -236,12 +240,7 @@ class FormalEvaluationScope {
236240
#ifndef NDEBUG
237241
inline void
238242
FormalEvaluationContext::checkCleanupDeactivation(CleanupHandle handle) {
239-
// Start at the innermost scope depth. Note that we pop scopes off the
240-
// stack before we start emitting their cleanups.
241-
if (!innermostScope) return;
242-
assert(!innermostScope->isPopped());
243-
for (auto i = find(*innermostScope->savedDepth), e = end(); i != e; ++i) {
244-
auto &access = *i;
243+
for (auto &access : *this) {
245244
assert((access.isFinished() || access.getCleanup() != handle) &&
246245
"popping active formal-evaluation cleanup");
247246
}

lib/SILGen/ManagedValue.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ ManagedValue ManagedValue::copyUnmanaged(SILGenFunction &SGF, SILLocation loc) {
8585
/// have cleanups. It returns a +1 value with one.
8686
ManagedValue ManagedValue::formalAccessCopyUnmanaged(SILGenFunction &SGF,
8787
SILLocation loc) {
88+
assert(SGF.isInFormalEvaluationScope());
89+
8890
if (getType().isObject()) {
8991
return SGF.B.createFormalAccessCopyValue(loc, *this);
9092
}
@@ -141,6 +143,7 @@ ManagedValue ManagedValue::borrow(SILGenFunction &SGF, SILLocation loc) const {
141143

142144
ManagedValue ManagedValue::formalAccessBorrow(SILGenFunction &SGF,
143145
SILLocation loc) const {
146+
assert(SGF.isInFormalEvaluationScope());
144147
assert(getValue() && "cannot borrow an invalid or in-context value");
145148
if (isLValue())
146149
return *this;

0 commit comments

Comments
 (0)