//===--- 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()), wasInWritebackScope(SGF.InWritebackScope), wasInInOutConversionScope(SGF.InInOutConversionScope) { if (wasInInOutConversionScope) { savedDepth.reset(); return; } SGF.InWritebackScope = true; } FormalEvaluationScope::FormalEvaluationScope(FormalEvaluationScope &&o) : SGF(o.SGF), savedDepth(o.savedDepth), wasInWritebackScope(o.wasInWritebackScope), wasInInOutConversionScope(o.wasInInOutConversionScope) { o.savedDepth.reset(); } void FormalEvaluationScope::popImpl() { // Pop the InWritebackScope bit. SGF.InWritebackScope = wasInWritebackScope; // 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(access); auto &rhs = static_cast(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 writebacks placed onto context during writeback 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()); } }