-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathFormalEvaluation.cpp
207 lines (172 loc) · 7.33 KB
/
FormalEvaluation.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//===--- FormalEvaluation.cpp ---------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "FormalEvaluation.h"
#include "LValue.h"
#include "SILGenFunction.h"
#include "swift/Basic/Assertions.h"
using namespace swift;
using namespace Lowering;
//===----------------------------------------------------------------------===//
// Formal Access
//===----------------------------------------------------------------------===//
void FormalAccess::_anchor() {}
void FormalAccess::verify(SILGenFunction &SGF) const {
#ifndef NDEBUG
// If this access was already finished, continue. This can happen if an
// owned formal access was forwarded.
if (isFinished()) {
assert(getKind() == FormalAccess::Owned &&
"Only owned formal accesses should be forwarded.");
// We can not check that our cleanup is actually dead since the cleanup
// may have been popped at this point and the stack may have new values.
return;
}
assert(!isFinished() && "Can not finish a formal access cleanup "
"twice");
// Now try to look up the cleanup handle of the formal access.
SGF.Cleanups.checkIterator(getCleanup());
#endif
}
//===----------------------------------------------------------------------===//
// Shared Borrow Formal Evaluation
//===----------------------------------------------------------------------===//
void SharedBorrowFormalAccess::finishImpl(SILGenFunction &SGF) {
SGF.B.createEndBorrow(CleanupLocation(loc), borrowedValue);
}
//===----------------------------------------------------------------------===//
// OwnedFormalAccess
//===----------------------------------------------------------------------===//
void OwnedFormalAccess::finishImpl(SILGenFunction &SGF) {
auto cleanupLoc = CleanupLocation(loc);
if (value->getType().isAddress())
SGF.B.createDestroyAddr(cleanupLoc, value);
else
SGF.B.emitDestroyValueOperation(cleanupLoc, value);
}
//===----------------------------------------------------------------------===//
// Formal Evaluation Scope
//===----------------------------------------------------------------------===//
FormalEvaluationScope::FormalEvaluationScope(SILGenFunction &SGF)
: SGF(SGF), savedDepth(SGF.FormalEvalContext.stable_begin()),
previous(SGF.FormalEvalContext.innermostScope),
wasInInOutConversionScope(SGF.InInOutConversionScope) {
if (wasInInOutConversionScope) {
savedDepth.reset();
assert(isPopped());
return;
}
SGF.FormalEvalContext.innermostScope = this;
}
FormalEvaluationScope::FormalEvaluationScope(FormalEvaluationScope &&o)
: SGF(o.SGF), savedDepth(o.savedDepth), previous(o.previous),
wasInInOutConversionScope(o.wasInInOutConversionScope) {
// Replace the scope in the active-scope chain if it's present.
if (!o.isPopped()) {
for (auto c = &SGF.FormalEvalContext.innermostScope; ; c = &(*c)->previous){
if (*c == &o) {
*c = this;
break;
}
}
}
o.savedDepth.reset();
assert(o.isPopped());
}
void FormalEvaluationScope::popImpl() {
auto &context = SGF.FormalEvalContext;
// Remove the innermost scope from the chain.
assert(context.innermostScope == this &&
"popping formal-evaluation scopes out of order");
context.innermostScope = previous;
auto endDepth = *savedDepth;
// Check to see if there is anything going on here.
if (endDepth == context.stable_begin())
return;
#ifndef NDEBUG
// Verify that all the accesses are valid.
for (auto i = context.begin(), e = context.find(endDepth); i != e; ++i) {
i->verify(SGF);
}
#endif
// Save our start point to make sure that we are not adding any new cleanups
// to the front of the stack.
auto originalBegin = context.stable_begin();
// Then working down the stack until we visit unwrappedSavedDepth...
auto i = originalBegin;
do {
// Grab the next evaluation.
FormalAccess &access = context.findAndAdvance(i);
// If this access was already finished, continue. This can happen if an
// owned formal access was forwarded.
if (access.isFinished()) {
assert(access.getKind() == FormalAccess::Owned &&
"Only owned formal accesses should be forwarded.");
// We can not check that our cleanup is actually dead since the cleanup
// may have been popped at this point and the stack may have new values.
continue;
}
assert(!access.isFinished() && "Can not finish a formal access cleanup "
"twice");
// Set the finished bit to appease various invariants.
access.setFinished();
// Deactivate the cleanup.
if (SGF.B.hasValidInsertionPoint()) {
SGF.Cleanups.setCleanupState(access.getCleanup(), CleanupState::Dead);
}
// Attempt to diagnose problems where obvious aliasing introduces illegal
// code. We do a simple N^2 comparison here to detect this because it is
// extremely unlikely more than a few writebacks are active at once.
if (access.getKind() == FormalAccess::Exclusive) {
// Note that we already advanced 'iter' above, so we can just start
// iterating from there. Also, this doesn't invalidate the iterators.
for (auto j = context.find(i), je = context.find(endDepth); j != je; ++j){
FormalAccess &other = *j;
if (other.getKind() != FormalAccess::Exclusive)
continue;
auto &lhs = static_cast<ExclusiveBorrowFormalAccess &>(access);
auto &rhs = static_cast<ExclusiveBorrowFormalAccess &>(other);
lhs.diagnoseConflict(rhs, SGF);
}
}
// Claim the address of each and then perform the writeback from the
// temporary allocation to the source we copied from.
//
// This evaluates arbitrary code, so it's best to be paranoid
// about iterators on the context.
if (SGF.B.hasValidInsertionPoint()) {
DiverseValueBuffer<FormalAccess> copiedAccess(access);
copiedAccess.getCopy().finish(SGF);
}
} while (i != endDepth);
// Then check that we did not add any additional cleanups to the beginning of
// the stack...
assert(originalBegin == context.stable_begin() &&
"pushed more formal evaluations while popping formal evaluations?!");
// And then pop off all stack elements until we reach the savedDepth.
context.pop(endDepth);
}
void FormalEvaluationScope::verify() const {
// Walk up the stack to the saved depth.
auto &context = SGF.FormalEvalContext;
for (auto i = context.begin(), e = context.find(*savedDepth); i != e; ++i) {
i->verify(SGF);
}
}
//===----------------------------------------------------------------------===//
// Formal Evaluation Context
//===----------------------------------------------------------------------===//
void FormalEvaluationContext::dump(SILGenFunction &SGF) {
for (auto II = begin(), IE = end(); II != IE; ++II) {
FormalAccess &access = *II;
SGF.Cleanups.dump(access.getCleanup());
}
}