mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user