1//===-- EHScopeStack.h - Stack for cleanup IR generation --------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// These classes should be the minimum interface required for other parts of
11// CodeGen to emit cleanups.  The implementation is in CGCleanup.cpp and other
12// implemenentation details that are not widely needed are in CGCleanup.h.
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H
17#define LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H
18
19#include "clang/Basic/LLVM.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/IR/BasicBlock.h"
23#include "llvm/IR/Instructions.h"
24#include "llvm/IR/Value.h"
25
26namespace clang {
27namespace CodeGen {
28
29class CodeGenFunction;
30
31/// A branch fixup.  These are required when emitting a goto to a
32/// label which hasn't been emitted yet.  The goto is optimistically
33/// emitted as a branch to the basic block for the label, and (if it
34/// occurs in a scope with non-trivial cleanups) a fixup is added to
35/// the innermost cleanup.  When a (normal) cleanup is popped, any
36/// unresolved fixups in that scope are threaded through the cleanup.
37struct BranchFixup {
38  /// The block containing the terminator which needs to be modified
39  /// into a switch if this fixup is resolved into the current scope.
40  /// If null, LatestBranch points directly to the destination.
41  llvm::BasicBlock *OptimisticBranchBlock;
42
43  /// The ultimate destination of the branch.
44  ///
45  /// This can be set to null to indicate that this fixup was
46  /// successfully resolved.
47  llvm::BasicBlock *Destination;
48
49  /// The destination index value.
50  unsigned DestinationIndex;
51
52  /// The initial branch of the fixup.
53  llvm::BranchInst *InitialBranch;
54};
55
56template <class T> struct InvariantValue {
57  typedef T type;
58  typedef T saved_type;
59  static bool needsSaving(type value) { return false; }
60  static saved_type save(CodeGenFunction &CGF, type value) { return value; }
61  static type restore(CodeGenFunction &CGF, saved_type value) { return value; }
62};
63
64/// A metaprogramming class for ensuring that a value will dominate an
65/// arbitrary position in a function.
66template <class T> struct DominatingValue : InvariantValue<T> {};
67
68template <class T, bool mightBeInstruction =
69            std::is_base_of<llvm::Value, T>::value &&
70            !std::is_base_of<llvm::Constant, T>::value &&
71            !std::is_base_of<llvm::BasicBlock, T>::value>
72struct DominatingPointer;
73template <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {};
74// template <class T> struct DominatingPointer<T,true> at end of file
75
76template <class T> struct DominatingValue<T*> : DominatingPointer<T> {};
77
78enum CleanupKind : unsigned {
79  /// Denotes a cleanup that should run when a scope is exited using exceptional
80  /// control flow (a throw statement leading to stack unwinding, ).
81  EHCleanup = 0x1,
82
83  /// Denotes a cleanup that should run when a scope is exited using normal
84  /// control flow (falling off the end of the scope, return, goto, ...).
85  NormalCleanup = 0x2,
86
87  NormalAndEHCleanup = EHCleanup | NormalCleanup,
88
89  InactiveCleanup = 0x4,
90  InactiveEHCleanup = EHCleanup | InactiveCleanup,
91  InactiveNormalCleanup = NormalCleanup | InactiveCleanup,
92  InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup
93};
94
95/// A stack of scopes which respond to exceptions, including cleanups
96/// and catch blocks.
97class EHScopeStack {
98public:
99  /* Should switch to alignof(uint64_t) instead of 8, when EHCleanupScope can */
100  enum { ScopeStackAlignment = 8 };
101
102  /// A saved depth on the scope stack.  This is necessary because
103  /// pushing scopes onto the stack invalidates iterators.
104  class stable_iterator {
105    friend class EHScopeStack;
106
107    /// Offset from StartOfData to EndOfBuffer.
108    ptrdiff_t Size;
109
110    stable_iterator(ptrdiff_t Size) : Size(Size) {}
111
112  public:
113    static stable_iterator invalid() { return stable_iterator(-1); }
114    stable_iterator() : Size(-1) {}
115
116    bool isValid() const { return Size >= 0; }
117
118    /// Returns true if this scope encloses I.
119    /// Returns false if I is invalid.
120    /// This scope must be valid.
121    bool encloses(stable_iterator I) const { return Size <= I.Size; }
122
123    /// Returns true if this scope strictly encloses I: that is,
124    /// if it encloses I and is not I.
125    /// Returns false is I is invalid.
126    /// This scope must be valid.
127    bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; }
128
129    friend bool operator==(stable_iterator A, stable_iterator B) {
130      return A.Size == B.Size;
131    }
132    friend bool operator!=(stable_iterator A, stable_iterator B) {
133      return A.Size != B.Size;
134    }
135  };
136
137  /// Information for lazily generating a cleanup.  Subclasses must be
138  /// POD-like: cleanups will not be destructed, and they will be
139  /// allocated on the cleanup stack and freely copied and moved
140  /// around.
141  ///
142  /// Cleanup implementations should generally be declared in an
143  /// anonymous namespace.
144  class Cleanup {
145    // Anchor the construction vtable.
146    virtual void anchor();
147
148  protected:
149    ~Cleanup() = default;
150
151  public:
152    Cleanup(const Cleanup &) = default;
153    Cleanup(Cleanup &&) {}
154    Cleanup() = default;
155
156    /// Generation flags.
157    class Flags {
158      enum {
159        F_IsForEH             = 0x1,
160        F_IsNormalCleanupKind = 0x2,
161        F_IsEHCleanupKind     = 0x4
162      };
163      unsigned flags;
164
165    public:
166      Flags() : flags(0) {}
167
168      /// isForEH - true if the current emission is for an EH cleanup.
169      bool isForEHCleanup() const { return flags & F_IsForEH; }
170      bool isForNormalCleanup() const { return !isForEHCleanup(); }
171      void setIsForEHCleanup() { flags |= F_IsForEH; }
172
173      bool isNormalCleanupKind() const { return flags & F_IsNormalCleanupKind; }
174      void setIsNormalCleanupKind() { flags |= F_IsNormalCleanupKind; }
175
176      /// isEHCleanupKind - true if the cleanup was pushed as an EH
177      /// cleanup.
178      bool isEHCleanupKind() const { return flags & F_IsEHCleanupKind; }
179      void setIsEHCleanupKind() { flags |= F_IsEHCleanupKind; }
180    };
181
182
183    /// Emit the cleanup.  For normal cleanups, this is run in the
184    /// same EH context as when the cleanup was pushed, i.e. the
185    /// immediately-enclosing context of the cleanup scope.  For
186    /// EH cleanups, this is run in a terminate context.
187    ///
188    // \param flags cleanup kind.
189    virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0;
190  };
191
192  /// ConditionalCleanup stores the saved form of its parameters,
193  /// then restores them and performs the cleanup.
194  template <class T, class... As>
195  class ConditionalCleanup final : public Cleanup {
196    typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple;
197    SavedTuple Saved;
198
199    template <std::size_t... Is>
200    T restore(CodeGenFunction &CGF, llvm::index_sequence<Is...>) {
201      // It's important that the restores are emitted in order. The braced init
202      // list guarentees that.
203      return T{DominatingValue<As>::restore(CGF, std::get<Is>(Saved))...};
204    }
205
206    void Emit(CodeGenFunction &CGF, Flags flags) override {
207      restore(CGF, llvm::index_sequence_for<As...>()).Emit(CGF, flags);
208    }
209
210  public:
211    ConditionalCleanup(typename DominatingValue<As>::saved_type... A)
212        : Saved(A...) {}
213
214    ConditionalCleanup(SavedTuple Tuple) : Saved(std::move(Tuple)) {}
215  };
216
217private:
218  // The implementation for this class is in CGException.h and
219  // CGException.cpp; the definition is here because it's used as a
220  // member of CodeGenFunction.
221
222  /// The start of the scope-stack buffer, i.e. the allocated pointer
223  /// for the buffer.  All of these pointers are either simultaneously
224  /// null or simultaneously valid.
225  char *StartOfBuffer;
226
227  /// The end of the buffer.
228  char *EndOfBuffer;
229
230  /// The first valid entry in the buffer.
231  char *StartOfData;
232
233  /// The innermost normal cleanup on the stack.
234  stable_iterator InnermostNormalCleanup;
235
236  /// The innermost EH scope on the stack.
237  stable_iterator InnermostEHScope;
238
239  /// The current set of branch fixups.  A branch fixup is a jump to
240  /// an as-yet unemitted label, i.e. a label for which we don't yet
241  /// know the EH stack depth.  Whenever we pop a cleanup, we have
242  /// to thread all the current branch fixups through it.
243  ///
244  /// Fixups are recorded as the Use of the respective branch or
245  /// switch statement.  The use points to the final destination.
246  /// When popping out of a cleanup, these uses are threaded through
247  /// the cleanup and adjusted to point to the new cleanup.
248  ///
249  /// Note that branches are allowed to jump into protected scopes
250  /// in certain situations;  e.g. the following code is legal:
251  ///     struct A { ~A(); }; // trivial ctor, non-trivial dtor
252  ///     goto foo;
253  ///     A a;
254  ///    foo:
255  ///     bar();
256  SmallVector<BranchFixup, 8> BranchFixups;
257
258  char *allocate(size_t Size);
259  void deallocate(size_t Size);
260
261  void *pushCleanup(CleanupKind K, size_t DataSize);
262
263public:
264  EHScopeStack() : StartOfBuffer(nullptr), EndOfBuffer(nullptr),
265                   StartOfData(nullptr), InnermostNormalCleanup(stable_end()),
266                   InnermostEHScope(stable_end()) {}
267  ~EHScopeStack() { delete[] StartOfBuffer; }
268
269  /// Push a lazily-created cleanup on the stack.
270  template <class T, class... As> void pushCleanup(CleanupKind Kind, As... A) {
271    static_assert(llvm::AlignOf<T>::Alignment <= ScopeStackAlignment,
272                  "Cleanup's alignment is too large.");
273    void *Buffer = pushCleanup(Kind, sizeof(T));
274    Cleanup *Obj = new (Buffer) T(A...);
275    (void) Obj;
276  }
277
278  /// Push a lazily-created cleanup on the stack. Tuple version.
279  template <class T, class... As>
280  void pushCleanupTuple(CleanupKind Kind, std::tuple<As...> A) {
281    static_assert(llvm::AlignOf<T>::Alignment <= ScopeStackAlignment,
282                  "Cleanup's alignment is too large.");
283    void *Buffer = pushCleanup(Kind, sizeof(T));
284    Cleanup *Obj = new (Buffer) T(std::move(A));
285    (void) Obj;
286  }
287
288  // Feel free to add more variants of the following:
289
290  /// Push a cleanup with non-constant storage requirements on the
291  /// stack.  The cleanup type must provide an additional static method:
292  ///   static size_t getExtraSize(size_t);
293  /// The argument to this method will be the value N, which will also
294  /// be passed as the first argument to the constructor.
295  ///
296  /// The data stored in the extra storage must obey the same
297  /// restrictions as normal cleanup member data.
298  ///
299  /// The pointer returned from this method is valid until the cleanup
300  /// stack is modified.
301  template <class T, class... As>
302  T *pushCleanupWithExtra(CleanupKind Kind, size_t N, As... A) {
303    static_assert(llvm::AlignOf<T>::Alignment <= ScopeStackAlignment,
304                  "Cleanup's alignment is too large.");
305    void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N));
306    return new (Buffer) T(N, A...);
307  }
308
309  void pushCopyOfCleanup(CleanupKind Kind, const void *Cleanup, size_t Size) {
310    void *Buffer = pushCleanup(Kind, Size);
311    std::memcpy(Buffer, Cleanup, Size);
312  }
313
314  /// Pops a cleanup scope off the stack.  This is private to CGCleanup.cpp.
315  void popCleanup();
316
317  /// Push a set of catch handlers on the stack.  The catch is
318  /// uninitialized and will need to have the given number of handlers
319  /// set on it.
320  class EHCatchScope *pushCatch(unsigned NumHandlers);
321
322  /// Pops a catch scope off the stack.  This is private to CGException.cpp.
323  void popCatch();
324
325  /// Push an exceptions filter on the stack.
326  class EHFilterScope *pushFilter(unsigned NumFilters);
327
328  /// Pops an exceptions filter off the stack.
329  void popFilter();
330
331  /// Push a terminate handler on the stack.
332  void pushTerminate();
333
334  /// Pops a terminate handler off the stack.
335  void popTerminate();
336
337  // Returns true iff the current scope is either empty or contains only
338  // lifetime markers, i.e. no real cleanup code
339  bool containsOnlyLifetimeMarkers(stable_iterator Old) const;
340
341  /// Determines whether the exception-scopes stack is empty.
342  bool empty() const { return StartOfData == EndOfBuffer; }
343
344  bool requiresLandingPad() const {
345    return InnermostEHScope != stable_end();
346  }
347
348  /// Determines whether there are any normal cleanups on the stack.
349  bool hasNormalCleanups() const {
350    return InnermostNormalCleanup != stable_end();
351  }
352
353  /// Returns the innermost normal cleanup on the stack, or
354  /// stable_end() if there are no normal cleanups.
355  stable_iterator getInnermostNormalCleanup() const {
356    return InnermostNormalCleanup;
357  }
358  stable_iterator getInnermostActiveNormalCleanup() const;
359
360  stable_iterator getInnermostEHScope() const {
361    return InnermostEHScope;
362  }
363
364
365  /// An unstable reference to a scope-stack depth.  Invalidated by
366  /// pushes but not pops.
367  class iterator;
368
369  /// Returns an iterator pointing to the innermost EH scope.
370  iterator begin() const;
371
372  /// Returns an iterator pointing to the outermost EH scope.
373  iterator end() const;
374
375  /// Create a stable reference to the top of the EH stack.  The
376  /// returned reference is valid until that scope is popped off the
377  /// stack.
378  stable_iterator stable_begin() const {
379    return stable_iterator(EndOfBuffer - StartOfData);
380  }
381
382  /// Create a stable reference to the bottom of the EH stack.
383  static stable_iterator stable_end() {
384    return stable_iterator(0);
385  }
386
387  /// Translates an iterator into a stable_iterator.
388  stable_iterator stabilize(iterator it) const;
389
390  /// Turn a stable reference to a scope depth into a unstable pointer
391  /// to the EH stack.
392  iterator find(stable_iterator save) const;
393
394  /// Add a branch fixup to the current cleanup scope.
395  BranchFixup &addBranchFixup() {
396    assert(hasNormalCleanups() && "adding fixup in scope without cleanups");
397    BranchFixups.push_back(BranchFixup());
398    return BranchFixups.back();
399  }
400
401  unsigned getNumBranchFixups() const { return BranchFixups.size(); }
402  BranchFixup &getBranchFixup(unsigned I) {
403    assert(I < getNumBranchFixups());
404    return BranchFixups[I];
405  }
406
407  /// Pops lazily-removed fixups from the end of the list.  This
408  /// should only be called by procedures which have just popped a
409  /// cleanup or resolved one or more fixups.
410  void popNullFixups();
411
412  /// Clears the branch-fixups list.  This should only be called by
413  /// ResolveAllBranchFixups.
414  void clearFixups() { BranchFixups.clear(); }
415};
416
417} // namespace CodeGen
418} // namespace clang
419
420#endif
421