1218887Sdim//===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim// These classes support the generation of LLVM IR for cleanups.
11218887Sdim//
12218887Sdim//===----------------------------------------------------------------------===//
13218887Sdim
14218887Sdim#ifndef CLANG_CODEGEN_CGCLEANUP_H
15218887Sdim#define CLANG_CODEGEN_CGCLEANUP_H
16218887Sdim
17263509Sdim#include "EHScopeStack.h"
18263509Sdim#include "llvm/ADT/SmallPtrSet.h"
19263509Sdim#include "llvm/ADT/SmallVector.h"
20218887Sdim
21218887Sdimnamespace llvm {
22263509Sdimclass BasicBlock;
23263509Sdimclass Value;
24263509Sdimclass ConstantInt;
25263509Sdimclass AllocaInst;
26218887Sdim}
27218887Sdim
28218887Sdimnamespace clang {
29218887Sdimnamespace CodeGen {
30218887Sdim
31218887Sdim/// A protected scope for zero-cost EH handling.
32218887Sdimclass EHScope {
33218887Sdim  llvm::BasicBlock *CachedLandingPad;
34226890Sdim  llvm::BasicBlock *CachedEHDispatchBlock;
35218887Sdim
36226890Sdim  EHScopeStack::stable_iterator EnclosingEHScope;
37218887Sdim
38226890Sdim  class CommonBitFields {
39226890Sdim    friend class EHScope;
40226890Sdim    unsigned Kind : 2;
41226890Sdim  };
42226890Sdim  enum { NumCommonBits = 2 };
43226890Sdim
44218887Sdimprotected:
45226890Sdim  class CatchBitFields {
46226890Sdim    friend class EHCatchScope;
47226890Sdim    unsigned : NumCommonBits;
48218887Sdim
49226890Sdim    unsigned NumHandlers : 32 - NumCommonBits;
50226890Sdim  };
51226890Sdim
52226890Sdim  class CleanupBitFields {
53226890Sdim    friend class EHCleanupScope;
54226890Sdim    unsigned : NumCommonBits;
55226890Sdim
56226890Sdim    /// Whether this cleanup needs to be run along normal edges.
57226890Sdim    unsigned IsNormalCleanup : 1;
58226890Sdim
59226890Sdim    /// Whether this cleanup needs to be run along exception edges.
60226890Sdim    unsigned IsEHCleanup : 1;
61226890Sdim
62226890Sdim    /// Whether this cleanup is currently active.
63226890Sdim    unsigned IsActive : 1;
64226890Sdim
65226890Sdim    /// Whether the normal cleanup should test the activation flag.
66226890Sdim    unsigned TestFlagInNormalCleanup : 1;
67226890Sdim
68226890Sdim    /// Whether the EH cleanup should test the activation flag.
69226890Sdim    unsigned TestFlagInEHCleanup : 1;
70226890Sdim
71226890Sdim    /// The amount of extra storage needed by the Cleanup.
72226890Sdim    /// Always a multiple of the scope-stack alignment.
73226890Sdim    unsigned CleanupSize : 12;
74226890Sdim
75226890Sdim    /// The number of fixups required by enclosing scopes (not including
76226890Sdim    /// this one).  If this is the top cleanup scope, all the fixups
77226890Sdim    /// from this index onwards belong to this scope.
78226890Sdim    unsigned FixupDepth : 32 - 17 - NumCommonBits; // currently 13
79226890Sdim  };
80226890Sdim
81226890Sdim  class FilterBitFields {
82226890Sdim    friend class EHFilterScope;
83226890Sdim    unsigned : NumCommonBits;
84226890Sdim
85226890Sdim    unsigned NumFilters : 32 - NumCommonBits;
86226890Sdim  };
87226890Sdim
88226890Sdim  union {
89226890Sdim    CommonBitFields CommonBits;
90226890Sdim    CatchBitFields CatchBits;
91226890Sdim    CleanupBitFields CleanupBits;
92226890Sdim    FilterBitFields FilterBits;
93226890Sdim  };
94226890Sdim
95218887Sdimpublic:
96218887Sdim  enum Kind { Cleanup, Catch, Terminate, Filter };
97218887Sdim
98226890Sdim  EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
99226890Sdim    : CachedLandingPad(0), CachedEHDispatchBlock(0),
100226890Sdim      EnclosingEHScope(enclosingEHScope) {
101226890Sdim    CommonBits.Kind = kind;
102226890Sdim  }
103218887Sdim
104226890Sdim  Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); }
105218887Sdim
106218887Sdim  llvm::BasicBlock *getCachedLandingPad() const {
107218887Sdim    return CachedLandingPad;
108218887Sdim  }
109218887Sdim
110226890Sdim  void setCachedLandingPad(llvm::BasicBlock *block) {
111226890Sdim    CachedLandingPad = block;
112218887Sdim  }
113226890Sdim
114226890Sdim  llvm::BasicBlock *getCachedEHDispatchBlock() const {
115226890Sdim    return CachedEHDispatchBlock;
116226890Sdim  }
117226890Sdim
118226890Sdim  void setCachedEHDispatchBlock(llvm::BasicBlock *block) {
119226890Sdim    CachedEHDispatchBlock = block;
120226890Sdim  }
121226890Sdim
122226890Sdim  bool hasEHBranches() const {
123226890Sdim    if (llvm::BasicBlock *block = getCachedEHDispatchBlock())
124226890Sdim      return !block->use_empty();
125226890Sdim    return false;
126226890Sdim  }
127226890Sdim
128226890Sdim  EHScopeStack::stable_iterator getEnclosingEHScope() const {
129226890Sdim    return EnclosingEHScope;
130226890Sdim  }
131218887Sdim};
132218887Sdim
133218887Sdim/// A scope which attempts to handle some, possibly all, types of
134218887Sdim/// exceptions.
135218887Sdim///
136245431Sdim/// Objective C \@finally blocks are represented using a cleanup scope
137218887Sdim/// after the catch scope.
138218887Sdimclass EHCatchScope : public EHScope {
139218887Sdim  // In effect, we have a flexible array member
140218887Sdim  //   Handler Handlers[0];
141218887Sdim  // But that's only standard in C99, not C++, so we have to do
142218887Sdim  // annoying pointer arithmetic instead.
143218887Sdim
144218887Sdimpublic:
145218887Sdim  struct Handler {
146218887Sdim    /// A type info value, or null (C++ null, not an LLVM null pointer)
147218887Sdim    /// for a catch-all.
148218887Sdim    llvm::Value *Type;
149218887Sdim
150218887Sdim    /// The catch handler for this type.
151218887Sdim    llvm::BasicBlock *Block;
152218887Sdim
153226890Sdim    bool isCatchAll() const { return Type == 0; }
154218887Sdim  };
155218887Sdim
156218887Sdimprivate:
157218887Sdim  friend class EHScopeStack;
158218887Sdim
159218887Sdim  Handler *getHandlers() {
160218887Sdim    return reinterpret_cast<Handler*>(this+1);
161218887Sdim  }
162218887Sdim
163218887Sdim  const Handler *getHandlers() const {
164218887Sdim    return reinterpret_cast<const Handler*>(this+1);
165218887Sdim  }
166218887Sdim
167218887Sdimpublic:
168218887Sdim  static size_t getSizeForNumHandlers(unsigned N) {
169218887Sdim    return sizeof(EHCatchScope) + N * sizeof(Handler);
170218887Sdim  }
171218887Sdim
172226890Sdim  EHCatchScope(unsigned numHandlers,
173226890Sdim               EHScopeStack::stable_iterator enclosingEHScope)
174226890Sdim    : EHScope(Catch, enclosingEHScope) {
175226890Sdim    CatchBits.NumHandlers = numHandlers;
176218887Sdim  }
177218887Sdim
178218887Sdim  unsigned getNumHandlers() const {
179226890Sdim    return CatchBits.NumHandlers;
180218887Sdim  }
181218887Sdim
182218887Sdim  void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
183218887Sdim    setHandler(I, /*catchall*/ 0, Block);
184218887Sdim  }
185218887Sdim
186218887Sdim  void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) {
187218887Sdim    assert(I < getNumHandlers());
188218887Sdim    getHandlers()[I].Type = Type;
189218887Sdim    getHandlers()[I].Block = Block;
190218887Sdim  }
191218887Sdim
192218887Sdim  const Handler &getHandler(unsigned I) const {
193218887Sdim    assert(I < getNumHandlers());
194218887Sdim    return getHandlers()[I];
195218887Sdim  }
196218887Sdim
197218887Sdim  typedef const Handler *iterator;
198218887Sdim  iterator begin() const { return getHandlers(); }
199218887Sdim  iterator end() const { return getHandlers() + getNumHandlers(); }
200218887Sdim
201218887Sdim  static bool classof(const EHScope *Scope) {
202218887Sdim    return Scope->getKind() == Catch;
203218887Sdim  }
204218887Sdim};
205218887Sdim
206218887Sdim/// A cleanup scope which generates the cleanup blocks lazily.
207218887Sdimclass EHCleanupScope : public EHScope {
208218887Sdim  /// The nearest normal cleanup scope enclosing this one.
209218887Sdim  EHScopeStack::stable_iterator EnclosingNormal;
210218887Sdim
211226890Sdim  /// The nearest EH scope enclosing this one.
212218887Sdim  EHScopeStack::stable_iterator EnclosingEH;
213218887Sdim
214218887Sdim  /// The dual entry/exit block along the normal edge.  This is lazily
215218887Sdim  /// created if needed before the cleanup is popped.
216218887Sdim  llvm::BasicBlock *NormalBlock;
217218887Sdim
218218887Sdim  /// An optional i1 variable indicating whether this cleanup has been
219218887Sdim  /// activated yet.
220218887Sdim  llvm::AllocaInst *ActiveFlag;
221218887Sdim
222218887Sdim  /// Extra information required for cleanups that have resolved
223218887Sdim  /// branches through them.  This has to be allocated on the side
224218887Sdim  /// because everything on the cleanup stack has be trivially
225218887Sdim  /// movable.
226218887Sdim  struct ExtInfo {
227218887Sdim    /// The destinations of normal branch-afters and branch-throughs.
228218887Sdim    llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
229218887Sdim
230218887Sdim    /// Normal branch-afters.
231226890Sdim    SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
232218887Sdim      BranchAfters;
233218887Sdim  };
234218887Sdim  mutable struct ExtInfo *ExtInfo;
235218887Sdim
236218887Sdim  struct ExtInfo &getExtInfo() {
237218887Sdim    if (!ExtInfo) ExtInfo = new struct ExtInfo();
238218887Sdim    return *ExtInfo;
239218887Sdim  }
240218887Sdim
241218887Sdim  const struct ExtInfo &getExtInfo() const {
242218887Sdim    if (!ExtInfo) ExtInfo = new struct ExtInfo();
243218887Sdim    return *ExtInfo;
244218887Sdim  }
245218887Sdim
246218887Sdimpublic:
247218887Sdim  /// Gets the size required for a lazy cleanup scope with the given
248218887Sdim  /// cleanup-data requirements.
249218887Sdim  static size_t getSizeForCleanupSize(size_t Size) {
250218887Sdim    return sizeof(EHCleanupScope) + Size;
251218887Sdim  }
252218887Sdim
253218887Sdim  size_t getAllocatedSize() const {
254226890Sdim    return sizeof(EHCleanupScope) + CleanupBits.CleanupSize;
255218887Sdim  }
256218887Sdim
257226890Sdim  EHCleanupScope(bool isNormal, bool isEH, bool isActive,
258226890Sdim                 unsigned cleanupSize, unsigned fixupDepth,
259226890Sdim                 EHScopeStack::stable_iterator enclosingNormal,
260226890Sdim                 EHScopeStack::stable_iterator enclosingEH)
261226890Sdim    : EHScope(EHScope::Cleanup, enclosingEH), EnclosingNormal(enclosingNormal),
262226890Sdim      NormalBlock(0), ActiveFlag(0), ExtInfo(0) {
263226890Sdim    CleanupBits.IsNormalCleanup = isNormal;
264226890Sdim    CleanupBits.IsEHCleanup = isEH;
265226890Sdim    CleanupBits.IsActive = isActive;
266226890Sdim    CleanupBits.TestFlagInNormalCleanup = false;
267226890Sdim    CleanupBits.TestFlagInEHCleanup = false;
268226890Sdim    CleanupBits.CleanupSize = cleanupSize;
269226890Sdim    CleanupBits.FixupDepth = fixupDepth;
270226890Sdim
271226890Sdim    assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow");
272218887Sdim  }
273218887Sdim
274218887Sdim  ~EHCleanupScope() {
275218887Sdim    delete ExtInfo;
276218887Sdim  }
277218887Sdim
278226890Sdim  bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; }
279218887Sdim  llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
280218887Sdim  void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
281218887Sdim
282226890Sdim  bool isEHCleanup() const { return CleanupBits.IsEHCleanup; }
283226890Sdim  llvm::BasicBlock *getEHBlock() const { return getCachedEHDispatchBlock(); }
284226890Sdim  void setEHBlock(llvm::BasicBlock *BB) { setCachedEHDispatchBlock(BB); }
285218887Sdim
286226890Sdim  bool isActive() const { return CleanupBits.IsActive; }
287226890Sdim  void setActive(bool A) { CleanupBits.IsActive = A; }
288218887Sdim
289218887Sdim  llvm::AllocaInst *getActiveFlag() const { return ActiveFlag; }
290218887Sdim  void setActiveFlag(llvm::AllocaInst *Var) { ActiveFlag = Var; }
291218887Sdim
292226890Sdim  void setTestFlagInNormalCleanup() {
293226890Sdim    CleanupBits.TestFlagInNormalCleanup = true;
294226890Sdim  }
295226890Sdim  bool shouldTestFlagInNormalCleanup() const {
296226890Sdim    return CleanupBits.TestFlagInNormalCleanup;
297226890Sdim  }
298218887Sdim
299226890Sdim  void setTestFlagInEHCleanup() {
300226890Sdim    CleanupBits.TestFlagInEHCleanup = true;
301226890Sdim  }
302226890Sdim  bool shouldTestFlagInEHCleanup() const {
303226890Sdim    return CleanupBits.TestFlagInEHCleanup;
304226890Sdim  }
305218887Sdim
306226890Sdim  unsigned getFixupDepth() const { return CleanupBits.FixupDepth; }
307218887Sdim  EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
308218887Sdim    return EnclosingNormal;
309218887Sdim  }
310218887Sdim
311226890Sdim  size_t getCleanupSize() const { return CleanupBits.CleanupSize; }
312218887Sdim  void *getCleanupBuffer() { return this + 1; }
313218887Sdim
314218887Sdim  EHScopeStack::Cleanup *getCleanup() {
315218887Sdim    return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
316218887Sdim  }
317218887Sdim
318218887Sdim  /// True if this cleanup scope has any branch-afters or branch-throughs.
319218887Sdim  bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
320218887Sdim
321218887Sdim  /// Add a branch-after to this cleanup scope.  A branch-after is a
322218887Sdim  /// branch from a point protected by this (normal) cleanup to a
323218887Sdim  /// point in the normal cleanup scope immediately containing it.
324218887Sdim  /// For example,
325218887Sdim  ///   for (;;) { A a; break; }
326218887Sdim  /// contains a branch-after.
327218887Sdim  ///
328218887Sdim  /// Branch-afters each have their own destination out of the
329218887Sdim  /// cleanup, guaranteed distinct from anything else threaded through
330218887Sdim  /// it.  Therefore branch-afters usually force a switch after the
331218887Sdim  /// cleanup.
332218887Sdim  void addBranchAfter(llvm::ConstantInt *Index,
333218887Sdim                      llvm::BasicBlock *Block) {
334218887Sdim    struct ExtInfo &ExtInfo = getExtInfo();
335218887Sdim    if (ExtInfo.Branches.insert(Block))
336218887Sdim      ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
337218887Sdim  }
338218887Sdim
339218887Sdim  /// Return the number of unique branch-afters on this scope.
340218887Sdim  unsigned getNumBranchAfters() const {
341218887Sdim    return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
342218887Sdim  }
343218887Sdim
344218887Sdim  llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
345218887Sdim    assert(I < getNumBranchAfters());
346218887Sdim    return ExtInfo->BranchAfters[I].first;
347218887Sdim  }
348218887Sdim
349218887Sdim  llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
350218887Sdim    assert(I < getNumBranchAfters());
351218887Sdim    return ExtInfo->BranchAfters[I].second;
352218887Sdim  }
353218887Sdim
354218887Sdim  /// Add a branch-through to this cleanup scope.  A branch-through is
355218887Sdim  /// a branch from a scope protected by this (normal) cleanup to an
356218887Sdim  /// enclosing scope other than the immediately-enclosing normal
357218887Sdim  /// cleanup scope.
358218887Sdim  ///
359218887Sdim  /// In the following example, the branch through B's scope is a
360218887Sdim  /// branch-through, while the branch through A's scope is a
361218887Sdim  /// branch-after:
362218887Sdim  ///   for (;;) { A a; B b; break; }
363218887Sdim  ///
364218887Sdim  /// All branch-throughs have a common destination out of the
365218887Sdim  /// cleanup, one possibly shared with the fall-through.  Therefore
366218887Sdim  /// branch-throughs usually don't force a switch after the cleanup.
367218887Sdim  ///
368218887Sdim  /// \return true if the branch-through was new to this scope
369218887Sdim  bool addBranchThrough(llvm::BasicBlock *Block) {
370218887Sdim    return getExtInfo().Branches.insert(Block);
371218887Sdim  }
372218887Sdim
373218887Sdim  /// Determines if this cleanup scope has any branch throughs.
374218887Sdim  bool hasBranchThroughs() const {
375218887Sdim    if (!ExtInfo) return false;
376218887Sdim    return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
377218887Sdim  }
378218887Sdim
379218887Sdim  static bool classof(const EHScope *Scope) {
380218887Sdim    return (Scope->getKind() == Cleanup);
381218887Sdim  }
382218887Sdim};
383218887Sdim
384218887Sdim/// An exceptions scope which filters exceptions thrown through it.
385218887Sdim/// Only exceptions matching the filter types will be permitted to be
386218887Sdim/// thrown.
387218887Sdim///
388218887Sdim/// This is used to implement C++ exception specifications.
389218887Sdimclass EHFilterScope : public EHScope {
390218887Sdim  // Essentially ends in a flexible array member:
391218887Sdim  // llvm::Value *FilterTypes[0];
392218887Sdim
393218887Sdim  llvm::Value **getFilters() {
394218887Sdim    return reinterpret_cast<llvm::Value**>(this+1);
395218887Sdim  }
396218887Sdim
397218887Sdim  llvm::Value * const *getFilters() const {
398218887Sdim    return reinterpret_cast<llvm::Value* const *>(this+1);
399218887Sdim  }
400218887Sdim
401218887Sdimpublic:
402226890Sdim  EHFilterScope(unsigned numFilters)
403226890Sdim    : EHScope(Filter, EHScopeStack::stable_end()) {
404226890Sdim    FilterBits.NumFilters = numFilters;
405226890Sdim  }
406218887Sdim
407226890Sdim  static size_t getSizeForNumFilters(unsigned numFilters) {
408226890Sdim    return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*);
409218887Sdim  }
410218887Sdim
411226890Sdim  unsigned getNumFilters() const { return FilterBits.NumFilters; }
412218887Sdim
413226890Sdim  void setFilter(unsigned i, llvm::Value *filterValue) {
414226890Sdim    assert(i < getNumFilters());
415226890Sdim    getFilters()[i] = filterValue;
416218887Sdim  }
417218887Sdim
418226890Sdim  llvm::Value *getFilter(unsigned i) const {
419226890Sdim    assert(i < getNumFilters());
420226890Sdim    return getFilters()[i];
421218887Sdim  }
422218887Sdim
423226890Sdim  static bool classof(const EHScope *scope) {
424226890Sdim    return scope->getKind() == Filter;
425218887Sdim  }
426218887Sdim};
427218887Sdim
428218887Sdim/// An exceptions scope which calls std::terminate if any exception
429218887Sdim/// reaches it.
430218887Sdimclass EHTerminateScope : public EHScope {
431218887Sdimpublic:
432226890Sdim  EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope)
433226890Sdim    : EHScope(Terminate, enclosingEHScope) {}
434218887Sdim  static size_t getSize() { return sizeof(EHTerminateScope); }
435218887Sdim
436226890Sdim  static bool classof(const EHScope *scope) {
437226890Sdim    return scope->getKind() == Terminate;
438218887Sdim  }
439218887Sdim};
440218887Sdim
441218887Sdim/// A non-stable pointer into the scope stack.
442218887Sdimclass EHScopeStack::iterator {
443218887Sdim  char *Ptr;
444218887Sdim
445218887Sdim  friend class EHScopeStack;
446218887Sdim  explicit iterator(char *Ptr) : Ptr(Ptr) {}
447218887Sdim
448218887Sdimpublic:
449218887Sdim  iterator() : Ptr(0) {}
450218887Sdim
451218887Sdim  EHScope *get() const {
452218887Sdim    return reinterpret_cast<EHScope*>(Ptr);
453218887Sdim  }
454218887Sdim
455218887Sdim  EHScope *operator->() const { return get(); }
456218887Sdim  EHScope &operator*() const { return *get(); }
457218887Sdim
458218887Sdim  iterator &operator++() {
459218887Sdim    switch (get()->getKind()) {
460218887Sdim    case EHScope::Catch:
461218887Sdim      Ptr += EHCatchScope::getSizeForNumHandlers(
462218887Sdim          static_cast<const EHCatchScope*>(get())->getNumHandlers());
463218887Sdim      break;
464218887Sdim
465218887Sdim    case EHScope::Filter:
466218887Sdim      Ptr += EHFilterScope::getSizeForNumFilters(
467218887Sdim          static_cast<const EHFilterScope*>(get())->getNumFilters());
468218887Sdim      break;
469218887Sdim
470218887Sdim    case EHScope::Cleanup:
471218887Sdim      Ptr += static_cast<const EHCleanupScope*>(get())
472218887Sdim        ->getAllocatedSize();
473218887Sdim      break;
474218887Sdim
475218887Sdim    case EHScope::Terminate:
476218887Sdim      Ptr += EHTerminateScope::getSize();
477218887Sdim      break;
478218887Sdim    }
479218887Sdim
480218887Sdim    return *this;
481218887Sdim  }
482218887Sdim
483218887Sdim  iterator next() {
484218887Sdim    iterator copy = *this;
485218887Sdim    ++copy;
486218887Sdim    return copy;
487218887Sdim  }
488218887Sdim
489218887Sdim  iterator operator++(int) {
490218887Sdim    iterator copy = *this;
491218887Sdim    operator++();
492218887Sdim    return copy;
493218887Sdim  }
494218887Sdim
495218887Sdim  bool encloses(iterator other) const { return Ptr >= other.Ptr; }
496218887Sdim  bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
497218887Sdim
498218887Sdim  bool operator==(iterator other) const { return Ptr == other.Ptr; }
499218887Sdim  bool operator!=(iterator other) const { return Ptr != other.Ptr; }
500218887Sdim};
501218887Sdim
502218887Sdiminline EHScopeStack::iterator EHScopeStack::begin() const {
503218887Sdim  return iterator(StartOfData);
504218887Sdim}
505218887Sdim
506218887Sdiminline EHScopeStack::iterator EHScopeStack::end() const {
507218887Sdim  return iterator(EndOfBuffer);
508218887Sdim}
509218887Sdim
510218887Sdiminline void EHScopeStack::popCatch() {
511218887Sdim  assert(!empty() && "popping exception stack when not empty");
512218887Sdim
513226890Sdim  EHCatchScope &scope = cast<EHCatchScope>(*begin());
514226890Sdim  InnermostEHScope = scope.getEnclosingEHScope();
515226890Sdim  StartOfData += EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers());
516218887Sdim}
517218887Sdim
518218887Sdiminline void EHScopeStack::popTerminate() {
519218887Sdim  assert(!empty() && "popping exception stack when not empty");
520218887Sdim
521226890Sdim  EHTerminateScope &scope = cast<EHTerminateScope>(*begin());
522226890Sdim  InnermostEHScope = scope.getEnclosingEHScope();
523218887Sdim  StartOfData += EHTerminateScope::getSize();
524218887Sdim}
525218887Sdim
526218887Sdiminline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
527218887Sdim  assert(sp.isValid() && "finding invalid savepoint");
528218887Sdim  assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
529218887Sdim  return iterator(EndOfBuffer - sp.Size);
530218887Sdim}
531218887Sdim
532218887Sdiminline EHScopeStack::stable_iterator
533218887SdimEHScopeStack::stabilize(iterator ir) const {
534218887Sdim  assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
535218887Sdim  return stable_iterator(EndOfBuffer - ir.Ptr);
536218887Sdim}
537218887Sdim
538218887Sdim}
539218887Sdim}
540218887Sdim
541218887Sdim#endif
542