| //===--- FormalEvaluation.h -------------------------------------*- C++ -*-===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_SILGEN_FORMALEVALUATION_H |
| #define SWIFT_SILGEN_FORMALEVALUATION_H |
| |
| #include "Cleanup.h" |
| #include "swift/Basic/DiverseStack.h" |
| #include "swift/SIL/SILValue.h" |
| #include "llvm/ADT/Optional.h" |
| |
| namespace swift { |
| namespace Lowering { |
| |
| class SILGenFunction; |
| class LogicalPathComponent; |
| |
| class FormalAccess { |
| public: |
| enum Kind { Shared, Exclusive, Owned, Unenforced }; |
| |
| private: |
| unsigned allocatedSize; |
| Kind kind; |
| |
| protected: |
| SILLocation loc; |
| CleanupHandle cleanup; |
| bool finished; |
| |
| FormalAccess(unsigned allocatedSize, Kind kind, SILLocation loc, |
| CleanupHandle cleanup) |
| : allocatedSize(allocatedSize), kind(kind), loc(loc), cleanup(cleanup), |
| finished(false) {} |
| |
| public: |
| virtual ~FormalAccess() {} |
| |
| // This anchor method serves three purposes: it aligns the class to |
| // a pointer boundary, it makes the class a primary base so that |
| // subclasses will be at offset zero, and it anchors the v-table |
| // to a specific file. |
| virtual void _anchor(); |
| |
| /// Return the allocated size of this object. This is required by |
| /// DiverseStack for iteration. |
| size_t allocated_size() const { return allocatedSize; } |
| |
| CleanupHandle getCleanup() const { return cleanup; } |
| |
| Kind getKind() const { return kind; } |
| |
| void finish(SILGenFunction &SGF) { finishImpl(SGF); } |
| |
| void setFinished() { finished = true; } |
| |
| bool isFinished() const { return finished; } |
| |
| void verify(SILGenFunction &SGF) const; |
| |
| protected: |
| virtual void finishImpl(SILGenFunction &SGF) = 0; |
| }; |
| |
| // FIXME: Misnomer. This is not used for borrowing a formal memory location |
| // (ExclusiveBorrowFormalAccess is always used for that). This is only used for |
| // formal access from a +0 value, which requires producing a "borrowed" |
| // SILValue. |
| class SharedBorrowFormalAccess : public FormalAccess { |
| SILValue originalValue; |
| SILValue borrowedValue; |
| |
| public: |
| SharedBorrowFormalAccess(SILLocation loc, CleanupHandle cleanup, |
| SILValue originalValue, SILValue borrowedValue) |
| : FormalAccess(sizeof(*this), FormalAccess::Shared, loc, cleanup), |
| originalValue(originalValue), borrowedValue(borrowedValue) {} |
| |
| SILValue getBorrowedValue() const { return borrowedValue; } |
| SILValue getOriginalValue() const { return originalValue; } |
| |
| private: |
| void finishImpl(SILGenFunction &SGF) override; |
| }; |
| |
| class OwnedFormalAccess : public FormalAccess { |
| SILValue value; |
| |
| public: |
| OwnedFormalAccess(SILLocation loc, CleanupHandle cleanup, SILValue value) |
| : FormalAccess(sizeof(*this), FormalAccess::Owned, loc, cleanup), |
| value(value) {} |
| |
| SILValue getValue() const { return value; } |
| |
| private: |
| void finishImpl(SILGenFunction &SGF) override; |
| }; |
| |
| class FormalEvaluationContext { |
| DiverseStack<FormalAccess, 128> stack; |
| |
| public: |
| using stable_iterator = decltype(stack)::stable_iterator; |
| using iterator = decltype(stack)::iterator; |
| |
| FormalEvaluationContext() : stack() {} |
| |
| // This is a type that can only be embedded in other types, it can not be |
| // moved or copied. |
| FormalEvaluationContext(const FormalEvaluationContext &) = delete; |
| FormalEvaluationContext(FormalEvaluationContext &&) = delete; |
| FormalEvaluationContext &operator=(const FormalEvaluationContext &) = delete; |
| FormalEvaluationContext &operator=(FormalEvaluationContext &&) = delete; |
| |
| ~FormalEvaluationContext() { |
| assert(stack.empty() && |
| "entries remaining on formal evaluation cleanup stack at end of function!"); |
| } |
| |
| iterator begin() { return stack.begin(); } |
| iterator end() { return stack.end(); } |
| stable_iterator stabilize(iterator iter) const { |
| return stack.stabilize(iter); |
| } |
| stable_iterator stable_begin() { return stabilize(begin()); } |
| iterator find(stable_iterator iter) { return stack.find(iter); } |
| |
| template <class U, class... ArgTypes> void push(ArgTypes &&... args) { |
| stack.push<U>(std::forward<ArgTypes>(args)...); |
| } |
| |
| void pop() { stack.pop(); } |
| |
| /// Pop objects off of the stack until \p the object pointed to by stable_iter |
| /// is the top element of the stack. |
| void pop(stable_iterator stable_iter) { stack.pop(stable_iter); } |
| |
| void dump(SILGenFunction &SGF); |
| }; |
| |
| /// A scope associated with the beginning of the formal evaluation of an lvalue. |
| /// |
| /// A formal evaluation of an lvalue occurs when emitting: |
| /// |
| /// 1. accessors. |
| /// 2. getters. |
| /// 3. materializeForSets. |
| /// |
| /// for lvalues. The general form of such an evaluation is: |
| /// |
| /// formally evaluate the lvalue "x" into memory |
| /// begin formal access to "x" |
| /// end formal access to "x" |
| /// ... *more formal access* |
| /// begin formal access to "x" |
| /// end formal access to "x" |
| /// end formal evaluation of lvalue into memory |
| /// |
| /// *NOTE* All formal access contain a pointer to a cleanup in the normal |
| /// cleanup stack. This is to ensure that when SILGen calls |
| /// Cleanups.emitBranchAndCleanups (and other special cleanup code along error |
| /// edges), writebacks are properly created. What is key to notice is that all |
| /// of these cleanup emission types are non-destructive. Contrast this with |
| /// normal scope popping. In such a case, the scope pop is destructive. This |
| /// means that any pointers from the formal access to the cleanup stack is now |
| /// invalid. |
| /// |
| /// In order to avoid this issue, it is important to /never/ create a formal |
| /// access cleanup when the "top level" scope is not a formal evaluation scope. |
| class FormalEvaluationScope { |
| SILGenFunction &SGF; |
| llvm::Optional<FormalEvaluationContext::stable_iterator> savedDepth; |
| bool wasInFormalEvaluationScope; |
| bool wasInInOutConversionScope; |
| |
| public: |
| FormalEvaluationScope(SILGenFunction &SGF); |
| ~FormalEvaluationScope() { |
| if (!savedDepth.hasValue()) |
| return; |
| popImpl(); |
| } |
| |
| bool isPopped() const { return !savedDepth.hasValue(); } |
| |
| void pop() { |
| if (wasInInOutConversionScope) |
| return; |
| |
| assert(!isPopped() && "popping an already-popped scope!"); |
| popImpl(); |
| savedDepth.reset(); |
| } |
| |
| FormalEvaluationScope(const FormalEvaluationScope &) = delete; |
| FormalEvaluationScope &operator=(const FormalEvaluationScope &) = delete; |
| |
| FormalEvaluationScope(FormalEvaluationScope &&o); |
| FormalEvaluationScope &operator=(FormalEvaluationScope &&o) = delete; |
| |
| /// Verify that we can successfully access all of the inner lexical scopes |
| /// that would be popped by this scope. |
| void verify() const; |
| |
| private: |
| void popImpl(); |
| }; |
| |
| } // namespace Lowering |
| } // namespace swift |
| |
| #endif |