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
|
//===--- 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"
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());
}
}
|