Emit unenforced access markers in SILGen for accesses to local temporaries.

These accesses can't be recognized as obviously local temporaries in the
verification pass, so the only way to exhaustively verify exclusivity is by
added unenforced markers.

SILGen currently only emits unenforced markers under -verify-exlcusivity. Once
opaque values is the only supported SILGen mode, then we should turn the markers
on by default (SILGen should not have different modes of operation).
This commit is contained in:
Andrew Trick
2017-12-11 19:44:36 -08:00
parent 34a968c334
commit 00b5a9db79
6 changed files with 232 additions and 21 deletions

View File

@@ -24,6 +24,7 @@
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/DiagnosticsCommon.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/PrettyStackTrace.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILUndef.h"
@@ -52,7 +53,7 @@ struct LValueWritebackCleanup : Cleanup {
void dump(SILGenFunction &) const override {
#ifndef NDEBUG
llvm::errs() << "LValueWritebackCleanup\n"
<< "State: " << getState() << "Depth: " << Depth.getDepth()
<< "State: " << getState() << " Depth: " << Depth.getDepth()
<< "\n";
#endif
}
@@ -266,6 +267,13 @@ ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &SGF,
ManagedValue temp = std::move(*this).materializeIntoTemporary(SGF, loc, base);
if (SGF.getOptions().VerifyExclusivity) {
// Begin an access of the temporary. It is unenforced because enforcement
// isn't required for RValues.
SILValue accessAddress = UnenforcedFormalAccess::enter(
SGF, loc, temp.getValue(), SILAccessKind::Modify);
temp = std::move(temp).transform(accessAddress);
}
// Push a writeback for the temporary.
pushWriteback(SGF, loc, std::move(clonedComponent), base,
MaterializedLValue(temp));
@@ -475,6 +483,93 @@ static SILValue enterAccessScope(SILGenFunction &SGF, SILLocation loc,
return addr;
}
// Find the base of the formal access at `address`. If the base requires an
// access marker, then create a begin_access on `address`. Return the
// address to be used for the access.
//
// FIXME: In order to generate more consistent and verifiable SIL patterns, or
// subobject projections, create the access on the base address and recreate the
// projection.
SILValue UnenforcedAccess::beginAccess(SILGenFunction &SGF, SILLocation loc,
SILValue address, SILAccessKind kind) {
if (!SGF.getOptions().VerifyExclusivity)
return address;
SILValue base = findAccessedAddressBase(address);
if (!base || !isPossibleFormalAccessBase(base))
return address;
auto BAI =
SGF.B.createBeginAccess(loc, address, kind, SILAccessEnforcement::Unsafe);
beginAccessPtr = BeginAccessPtr(BAI, DeleterCheck());
return BAI;
}
void UnenforcedAccess::endAccess(SILGenFunction &SGF) {
emitEndAccess(SGF);
beginAccessPtr.release();
}
void UnenforcedAccess::emitEndAccess(SILGenFunction &SGF) {
if (!beginAccessPtr)
return;
SGF.B.createEndAccess(beginAccessPtr->getLoc(), beginAccessPtr.get(),
/*abort*/ false);
}
// Emit an end_access marker when executing a cleanup (on a side branch).
void UnenforcedFormalAccess::emitEndAccess(SILGenFunction &SGF) {
access.emitEndAccess(SGF);
}
// End the access when existing the FormalEvaluationScope.
void UnenforcedFormalAccess::finishImpl(SILGenFunction &SGF) {
access.endAccess(SGF);
}
namespace {
struct UnenforcedAccessCleanup : Cleanup {
FormalEvaluationContext::stable_iterator Depth;
UnenforcedAccessCleanup() : Depth() {}
void emit(SILGenFunction &SGF, CleanupLocation loc) override {
auto &evaluation = *SGF.FormalEvalContext.find(Depth);
assert(evaluation.getKind() == FormalAccess::Unenforced);
auto &formalAccess = static_cast<UnenforcedFormalAccess &>(evaluation);
formalAccess.emitEndAccess(SGF);
}
void dump(SILGenFunction &) const override {
#ifndef NDEBUG
llvm::errs() << "UnenforcedAccessCleanup\n"
<< "State: " << getState() << " Depth: " << Depth.getDepth()
<< "\n";
#endif
}
};
} // end anonymous namespace
SILValue UnenforcedFormalAccess::enter(SILGenFunction &SGF, SILLocation loc,
SILValue address, SILAccessKind kind) {
assert(SGF.InFormalEvaluationScope);
UnenforcedAccess access;
SILValue accessAddress = access.beginAccess(SGF, loc, address, kind);
if (!access.beginAccessPtr)
return address;
auto &cleanup = SGF.Cleanups.pushCleanup<UnenforcedAccessCleanup>();
CleanupHandle handle = SGF.Cleanups.getTopCleanup();
auto &context = SGF.FormalEvalContext;
context.push<UnenforcedFormalAccess>(loc, std::move(access), handle);
cleanup.Depth = context.stable_begin();
return accessAddress;
}
namespace {
class RefElementComponent : public PhysicalPathComponent {
VarDecl *Field;
@@ -1259,6 +1354,7 @@ namespace {
// indirectly.
SILValue baseAddress;
SILValue baseMetatype;
UnenforcedAccess baseAccess;
if (base) {
if (base.getType().isAddress()) {
baseAddress = base.getValue();
@@ -1269,6 +1365,10 @@ namespace {
baseFormalType);
baseAddress = SGF.emitTemporaryAllocation(loc, base.getType());
// Create an unenforced formal access for the temporary base, which
// is passed @inout to the callback.
baseAddress = baseAccess.beginAccess(SGF, loc, baseAddress,
SILAccessKind::Modify);
if (base.getOwnershipKind() == ValueOwnershipKind::Guaranteed) {
SGF.B.createStoreBorrow(loc, base.getValue(), baseAddress);
} else {
@@ -1298,6 +1398,9 @@ namespace {
baseAddress,
baseMetatype
}, false);
if (baseAccess.beginAccessPtr)
baseAccess.endAccess(SGF);
}
// Continue.