| //===--- 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::get(loc), borrowedValue, |
| originalValue); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // OwnedFormalAccess |
| //===----------------------------------------------------------------------===// |
| |
| void OwnedFormalAccess::finishImpl(SILGenFunction &SGF) { |
| auto cleanupLoc = CleanupLocation::get(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()), |
| wasInFormalEvaluationScope(SGF.InFormalEvaluationScope), |
| wasInInOutConversionScope(SGF.InInOutConversionScope) { |
| if (wasInInOutConversionScope) { |
| savedDepth.reset(); |
| return; |
| } |
| SGF.InFormalEvaluationScope = true; |
| } |
| |
| FormalEvaluationScope::FormalEvaluationScope(FormalEvaluationScope &&o) |
| : SGF(o.SGF), savedDepth(o.savedDepth), |
| wasInFormalEvaluationScope(o.wasInFormalEvaluationScope), |
| wasInInOutConversionScope(o.wasInInOutConversionScope) { |
| o.savedDepth.reset(); |
| } |
| |
| void FormalEvaluationScope::popImpl() { |
| // Pop the SGF.InFormalEvaluationScope bit. |
| SGF.InFormalEvaluationScope = wasInFormalEvaluationScope; |
| |
| // Check to see if there is anything going on here. |
| |
| auto &context = SGF.FormalEvalContext; |
| using iterator = FormalEvaluationContext::iterator; |
| using stable_iterator = FormalEvaluationContext::stable_iterator; |
| |
| iterator unwrappedSavedDepth = context.find(savedDepth.getValue()); |
| iterator iter = context.begin(); |
| if (iter == unwrappedSavedDepth) |
| return; |
| |
| // Save our start point to make sure that we are not adding any new cleanups |
| // to the front of the stack. |
| stable_iterator originalBegin = context.stable_begin(); |
| (void)originalBegin; |
| |
| // Then working down the stack until we visit unwrappedSavedDepth... |
| for (; iter != unwrappedSavedDepth; ++iter) { |
| // Grab the next evaluation... |
| FormalAccess &access = *iter; |
| |
| // 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"); |
| |
| // and deactivate the cleanup. This will set the isFinished bit for owned |
| // FormalAccess. |
| 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) { |
| iterator j = iter; |
| ++j; |
| |
| for (; j != unwrappedSavedDepth; ++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. |
| access.finish(SGF); |
| } |
| |
| // Then check that we did not add any additional cleanups to the beginning of |
| // the stack... |
| assert(originalBegin == context.stable_begin() && |
| "more formal eval cleanups placed onto context during formal eval scope pop?!"); |
| |
| // And then pop off all stack elements until we reach the savedDepth. |
| context.pop(savedDepth.getValue()); |
| } |
| |
| void FormalEvaluationScope::verify() const { |
| // Check to see if there is anything going on here. |
| auto &context = SGF.FormalEvalContext; |
| using iterator = FormalEvaluationContext::iterator; |
| |
| iterator unwrappedSavedDepth = context.find(savedDepth.getValue()); |
| iterator iter = context.begin(); |
| if (iter == unwrappedSavedDepth) |
| return; |
| |
| // Then working down the stack until we visit unwrappedSavedDepth... |
| for (; iter != unwrappedSavedDepth; ++iter) { |
| // Grab the next evaluation verify that we can successfully access this |
| // formal access. |
| (*iter).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()); |
| } |
| } |