CGCleanup.h revision 218887
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
17218887Sdim/// EHScopeStack is defined in CodeGenFunction.h, but its
18218887Sdim/// implementation is in this file and in CGCleanup.cpp.
19218887Sdim#include "CodeGenFunction.h"
20218887Sdim
21218887Sdimnamespace llvm {
22218887Sdim  class Value;
23218887Sdim  class BasicBlock;
24218887Sdim}
25218887Sdim
26218887Sdimnamespace clang {
27218887Sdimnamespace CodeGen {
28218887Sdim
29218887Sdim/// A protected scope for zero-cost EH handling.
30218887Sdimclass EHScope {
31218887Sdim  llvm::BasicBlock *CachedLandingPad;
32218887Sdim
33218887Sdim  unsigned K : 2;
34218887Sdim
35218887Sdimprotected:
36218887Sdim  enum { BitsRemaining = 30 };
37218887Sdim
38218887Sdimpublic:
39218887Sdim  enum Kind { Cleanup, Catch, Terminate, Filter };
40218887Sdim
41218887Sdim  EHScope(Kind K) : CachedLandingPad(0), K(K) {}
42218887Sdim
43218887Sdim  Kind getKind() const { return static_cast<Kind>(K); }
44218887Sdim
45218887Sdim  llvm::BasicBlock *getCachedLandingPad() const {
46218887Sdim    return CachedLandingPad;
47218887Sdim  }
48218887Sdim
49218887Sdim  void setCachedLandingPad(llvm::BasicBlock *Block) {
50218887Sdim    CachedLandingPad = Block;
51218887Sdim  }
52218887Sdim};
53218887Sdim
54218887Sdim/// A scope which attempts to handle some, possibly all, types of
55218887Sdim/// exceptions.
56218887Sdim///
57218887Sdim/// Objective C @finally blocks are represented using a cleanup scope
58218887Sdim/// after the catch scope.
59218887Sdimclass EHCatchScope : public EHScope {
60218887Sdim  unsigned NumHandlers : BitsRemaining;
61218887Sdim
62218887Sdim  // In effect, we have a flexible array member
63218887Sdim  //   Handler Handlers[0];
64218887Sdim  // But that's only standard in C99, not C++, so we have to do
65218887Sdim  // annoying pointer arithmetic instead.
66218887Sdim
67218887Sdimpublic:
68218887Sdim  struct Handler {
69218887Sdim    /// A type info value, or null (C++ null, not an LLVM null pointer)
70218887Sdim    /// for a catch-all.
71218887Sdim    llvm::Value *Type;
72218887Sdim
73218887Sdim    /// The catch handler for this type.
74218887Sdim    llvm::BasicBlock *Block;
75218887Sdim
76218887Sdim    /// The unwind destination index for this handler.
77218887Sdim    unsigned Index;
78218887Sdim  };
79218887Sdim
80218887Sdimprivate:
81218887Sdim  friend class EHScopeStack;
82218887Sdim
83218887Sdim  Handler *getHandlers() {
84218887Sdim    return reinterpret_cast<Handler*>(this+1);
85218887Sdim  }
86218887Sdim
87218887Sdim  const Handler *getHandlers() const {
88218887Sdim    return reinterpret_cast<const Handler*>(this+1);
89218887Sdim  }
90218887Sdim
91218887Sdimpublic:
92218887Sdim  static size_t getSizeForNumHandlers(unsigned N) {
93218887Sdim    return sizeof(EHCatchScope) + N * sizeof(Handler);
94218887Sdim  }
95218887Sdim
96218887Sdim  EHCatchScope(unsigned NumHandlers)
97218887Sdim    : EHScope(Catch), NumHandlers(NumHandlers) {
98218887Sdim  }
99218887Sdim
100218887Sdim  unsigned getNumHandlers() const {
101218887Sdim    return NumHandlers;
102218887Sdim  }
103218887Sdim
104218887Sdim  void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
105218887Sdim    setHandler(I, /*catchall*/ 0, Block);
106218887Sdim  }
107218887Sdim
108218887Sdim  void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) {
109218887Sdim    assert(I < getNumHandlers());
110218887Sdim    getHandlers()[I].Type = Type;
111218887Sdim    getHandlers()[I].Block = Block;
112218887Sdim  }
113218887Sdim
114218887Sdim  const Handler &getHandler(unsigned I) const {
115218887Sdim    assert(I < getNumHandlers());
116218887Sdim    return getHandlers()[I];
117218887Sdim  }
118218887Sdim
119218887Sdim  typedef const Handler *iterator;
120218887Sdim  iterator begin() const { return getHandlers(); }
121218887Sdim  iterator end() const { return getHandlers() + getNumHandlers(); }
122218887Sdim
123218887Sdim  static bool classof(const EHScope *Scope) {
124218887Sdim    return Scope->getKind() == Catch;
125218887Sdim  }
126218887Sdim};
127218887Sdim
128218887Sdim/// A cleanup scope which generates the cleanup blocks lazily.
129218887Sdimclass EHCleanupScope : public EHScope {
130218887Sdim  /// Whether this cleanup needs to be run along normal edges.
131218887Sdim  bool IsNormalCleanup : 1;
132218887Sdim
133218887Sdim  /// Whether this cleanup needs to be run along exception edges.
134218887Sdim  bool IsEHCleanup : 1;
135218887Sdim
136218887Sdim  /// Whether this cleanup is currently active.
137218887Sdim  bool IsActive : 1;
138218887Sdim
139218887Sdim  /// Whether the normal cleanup should test the activation flag.
140218887Sdim  bool TestFlagInNormalCleanup : 1;
141218887Sdim
142218887Sdim  /// Whether the EH cleanup should test the activation flag.
143218887Sdim  bool TestFlagInEHCleanup : 1;
144218887Sdim
145218887Sdim  /// The amount of extra storage needed by the Cleanup.
146218887Sdim  /// Always a multiple of the scope-stack alignment.
147218887Sdim  unsigned CleanupSize : 12;
148218887Sdim
149218887Sdim  /// The number of fixups required by enclosing scopes (not including
150218887Sdim  /// this one).  If this is the top cleanup scope, all the fixups
151218887Sdim  /// from this index onwards belong to this scope.
152218887Sdim  unsigned FixupDepth : BitsRemaining - 17; // currently 13
153218887Sdim
154218887Sdim  /// The nearest normal cleanup scope enclosing this one.
155218887Sdim  EHScopeStack::stable_iterator EnclosingNormal;
156218887Sdim
157218887Sdim  /// The nearest EH cleanup scope enclosing this one.
158218887Sdim  EHScopeStack::stable_iterator EnclosingEH;
159218887Sdim
160218887Sdim  /// The dual entry/exit block along the normal edge.  This is lazily
161218887Sdim  /// created if needed before the cleanup is popped.
162218887Sdim  llvm::BasicBlock *NormalBlock;
163218887Sdim
164218887Sdim  /// The dual entry/exit block along the EH edge.  This is lazily
165218887Sdim  /// created if needed before the cleanup is popped.
166218887Sdim  llvm::BasicBlock *EHBlock;
167218887Sdim
168218887Sdim  /// An optional i1 variable indicating whether this cleanup has been
169218887Sdim  /// activated yet.
170218887Sdim  llvm::AllocaInst *ActiveFlag;
171218887Sdim
172218887Sdim  /// Extra information required for cleanups that have resolved
173218887Sdim  /// branches through them.  This has to be allocated on the side
174218887Sdim  /// because everything on the cleanup stack has be trivially
175218887Sdim  /// movable.
176218887Sdim  struct ExtInfo {
177218887Sdim    /// The destinations of normal branch-afters and branch-throughs.
178218887Sdim    llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
179218887Sdim
180218887Sdim    /// Normal branch-afters.
181218887Sdim    llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
182218887Sdim      BranchAfters;
183218887Sdim
184218887Sdim    /// The destinations of EH branch-afters and branch-throughs.
185218887Sdim    /// TODO: optimize for the extremely common case of a single
186218887Sdim    /// branch-through.
187218887Sdim    llvm::SmallPtrSet<llvm::BasicBlock*, 4> EHBranches;
188218887Sdim
189218887Sdim    /// EH branch-afters.
190218887Sdim    llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
191218887Sdim    EHBranchAfters;
192218887Sdim  };
193218887Sdim  mutable struct ExtInfo *ExtInfo;
194218887Sdim
195218887Sdim  struct ExtInfo &getExtInfo() {
196218887Sdim    if (!ExtInfo) ExtInfo = new struct ExtInfo();
197218887Sdim    return *ExtInfo;
198218887Sdim  }
199218887Sdim
200218887Sdim  const struct ExtInfo &getExtInfo() const {
201218887Sdim    if (!ExtInfo) ExtInfo = new struct ExtInfo();
202218887Sdim    return *ExtInfo;
203218887Sdim  }
204218887Sdim
205218887Sdimpublic:
206218887Sdim  /// Gets the size required for a lazy cleanup scope with the given
207218887Sdim  /// cleanup-data requirements.
208218887Sdim  static size_t getSizeForCleanupSize(size_t Size) {
209218887Sdim    return sizeof(EHCleanupScope) + Size;
210218887Sdim  }
211218887Sdim
212218887Sdim  size_t getAllocatedSize() const {
213218887Sdim    return sizeof(EHCleanupScope) + CleanupSize;
214218887Sdim  }
215218887Sdim
216218887Sdim  EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive,
217218887Sdim                 unsigned CleanupSize, unsigned FixupDepth,
218218887Sdim                 EHScopeStack::stable_iterator EnclosingNormal,
219218887Sdim                 EHScopeStack::stable_iterator EnclosingEH)
220218887Sdim    : EHScope(EHScope::Cleanup),
221218887Sdim      IsNormalCleanup(IsNormal), IsEHCleanup(IsEH), IsActive(IsActive),
222218887Sdim      TestFlagInNormalCleanup(false), TestFlagInEHCleanup(false),
223218887Sdim      CleanupSize(CleanupSize), FixupDepth(FixupDepth),
224218887Sdim      EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
225218887Sdim      NormalBlock(0), EHBlock(0), ActiveFlag(0), ExtInfo(0)
226218887Sdim  {
227218887Sdim    assert(this->CleanupSize == CleanupSize && "cleanup size overflow");
228218887Sdim  }
229218887Sdim
230218887Sdim  ~EHCleanupScope() {
231218887Sdim    delete ExtInfo;
232218887Sdim  }
233218887Sdim
234218887Sdim  bool isNormalCleanup() const { return IsNormalCleanup; }
235218887Sdim  llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
236218887Sdim  void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
237218887Sdim
238218887Sdim  bool isEHCleanup() const { return IsEHCleanup; }
239218887Sdim  llvm::BasicBlock *getEHBlock() const { return EHBlock; }
240218887Sdim  void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; }
241218887Sdim
242218887Sdim  bool isActive() const { return IsActive; }
243218887Sdim  void setActive(bool A) { IsActive = A; }
244218887Sdim
245218887Sdim  llvm::AllocaInst *getActiveFlag() const { return ActiveFlag; }
246218887Sdim  void setActiveFlag(llvm::AllocaInst *Var) { ActiveFlag = Var; }
247218887Sdim
248218887Sdim  void setTestFlagInNormalCleanup() { TestFlagInNormalCleanup = true; }
249218887Sdim  bool shouldTestFlagInNormalCleanup() const { return TestFlagInNormalCleanup; }
250218887Sdim
251218887Sdim  void setTestFlagInEHCleanup() { TestFlagInEHCleanup = true; }
252218887Sdim  bool shouldTestFlagInEHCleanup() const { return TestFlagInEHCleanup; }
253218887Sdim
254218887Sdim  unsigned getFixupDepth() const { return FixupDepth; }
255218887Sdim  EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
256218887Sdim    return EnclosingNormal;
257218887Sdim  }
258218887Sdim  EHScopeStack::stable_iterator getEnclosingEHCleanup() const {
259218887Sdim    return EnclosingEH;
260218887Sdim  }
261218887Sdim
262218887Sdim  size_t getCleanupSize() const { return CleanupSize; }
263218887Sdim  void *getCleanupBuffer() { return this + 1; }
264218887Sdim
265218887Sdim  EHScopeStack::Cleanup *getCleanup() {
266218887Sdim    return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
267218887Sdim  }
268218887Sdim
269218887Sdim  /// True if this cleanup scope has any branch-afters or branch-throughs.
270218887Sdim  bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
271218887Sdim
272218887Sdim  /// Add a branch-after to this cleanup scope.  A branch-after is a
273218887Sdim  /// branch from a point protected by this (normal) cleanup to a
274218887Sdim  /// point in the normal cleanup scope immediately containing it.
275218887Sdim  /// For example,
276218887Sdim  ///   for (;;) { A a; break; }
277218887Sdim  /// contains a branch-after.
278218887Sdim  ///
279218887Sdim  /// Branch-afters each have their own destination out of the
280218887Sdim  /// cleanup, guaranteed distinct from anything else threaded through
281218887Sdim  /// it.  Therefore branch-afters usually force a switch after the
282218887Sdim  /// cleanup.
283218887Sdim  void addBranchAfter(llvm::ConstantInt *Index,
284218887Sdim                      llvm::BasicBlock *Block) {
285218887Sdim    struct ExtInfo &ExtInfo = getExtInfo();
286218887Sdim    if (ExtInfo.Branches.insert(Block))
287218887Sdim      ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
288218887Sdim  }
289218887Sdim
290218887Sdim  /// Return the number of unique branch-afters on this scope.
291218887Sdim  unsigned getNumBranchAfters() const {
292218887Sdim    return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
293218887Sdim  }
294218887Sdim
295218887Sdim  llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
296218887Sdim    assert(I < getNumBranchAfters());
297218887Sdim    return ExtInfo->BranchAfters[I].first;
298218887Sdim  }
299218887Sdim
300218887Sdim  llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
301218887Sdim    assert(I < getNumBranchAfters());
302218887Sdim    return ExtInfo->BranchAfters[I].second;
303218887Sdim  }
304218887Sdim
305218887Sdim  /// Add a branch-through to this cleanup scope.  A branch-through is
306218887Sdim  /// a branch from a scope protected by this (normal) cleanup to an
307218887Sdim  /// enclosing scope other than the immediately-enclosing normal
308218887Sdim  /// cleanup scope.
309218887Sdim  ///
310218887Sdim  /// In the following example, the branch through B's scope is a
311218887Sdim  /// branch-through, while the branch through A's scope is a
312218887Sdim  /// branch-after:
313218887Sdim  ///   for (;;) { A a; B b; break; }
314218887Sdim  ///
315218887Sdim  /// All branch-throughs have a common destination out of the
316218887Sdim  /// cleanup, one possibly shared with the fall-through.  Therefore
317218887Sdim  /// branch-throughs usually don't force a switch after the cleanup.
318218887Sdim  ///
319218887Sdim  /// \return true if the branch-through was new to this scope
320218887Sdim  bool addBranchThrough(llvm::BasicBlock *Block) {
321218887Sdim    return getExtInfo().Branches.insert(Block);
322218887Sdim  }
323218887Sdim
324218887Sdim  /// Determines if this cleanup scope has any branch throughs.
325218887Sdim  bool hasBranchThroughs() const {
326218887Sdim    if (!ExtInfo) return false;
327218887Sdim    return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
328218887Sdim  }
329218887Sdim
330218887Sdim  // Same stuff, only for EH branches instead of normal branches.
331218887Sdim  // It's quite possible that we could find a better representation
332218887Sdim  // for this.
333218887Sdim
334218887Sdim  bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); }
335218887Sdim  void addEHBranchAfter(llvm::ConstantInt *Index,
336218887Sdim                        llvm::BasicBlock *Block) {
337218887Sdim    struct ExtInfo &ExtInfo = getExtInfo();
338218887Sdim    if (ExtInfo.EHBranches.insert(Block))
339218887Sdim      ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index));
340218887Sdim  }
341218887Sdim
342218887Sdim  unsigned getNumEHBranchAfters() const {
343218887Sdim    return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0;
344218887Sdim  }
345218887Sdim
346218887Sdim  llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const {
347218887Sdim    assert(I < getNumEHBranchAfters());
348218887Sdim    return ExtInfo->EHBranchAfters[I].first;
349218887Sdim  }
350218887Sdim
351218887Sdim  llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const {
352218887Sdim    assert(I < getNumEHBranchAfters());
353218887Sdim    return ExtInfo->EHBranchAfters[I].second;
354218887Sdim  }
355218887Sdim
356218887Sdim  bool addEHBranchThrough(llvm::BasicBlock *Block) {
357218887Sdim    return getExtInfo().EHBranches.insert(Block);
358218887Sdim  }
359218887Sdim
360218887Sdim  bool hasEHBranchThroughs() const {
361218887Sdim    if (!ExtInfo) return false;
362218887Sdim    return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size());
363218887Sdim  }
364218887Sdim
365218887Sdim  static bool classof(const EHScope *Scope) {
366218887Sdim    return (Scope->getKind() == Cleanup);
367218887Sdim  }
368218887Sdim};
369218887Sdim
370218887Sdim/// An exceptions scope which filters exceptions thrown through it.
371218887Sdim/// Only exceptions matching the filter types will be permitted to be
372218887Sdim/// thrown.
373218887Sdim///
374218887Sdim/// This is used to implement C++ exception specifications.
375218887Sdimclass EHFilterScope : public EHScope {
376218887Sdim  unsigned NumFilters : BitsRemaining;
377218887Sdim
378218887Sdim  // Essentially ends in a flexible array member:
379218887Sdim  // llvm::Value *FilterTypes[0];
380218887Sdim
381218887Sdim  llvm::Value **getFilters() {
382218887Sdim    return reinterpret_cast<llvm::Value**>(this+1);
383218887Sdim  }
384218887Sdim
385218887Sdim  llvm::Value * const *getFilters() const {
386218887Sdim    return reinterpret_cast<llvm::Value* const *>(this+1);
387218887Sdim  }
388218887Sdim
389218887Sdimpublic:
390218887Sdim  EHFilterScope(unsigned NumFilters) :
391218887Sdim    EHScope(Filter), NumFilters(NumFilters) {}
392218887Sdim
393218887Sdim  static size_t getSizeForNumFilters(unsigned NumFilters) {
394218887Sdim    return sizeof(EHFilterScope) + NumFilters * sizeof(llvm::Value*);
395218887Sdim  }
396218887Sdim
397218887Sdim  unsigned getNumFilters() const { return NumFilters; }
398218887Sdim
399218887Sdim  void setFilter(unsigned I, llvm::Value *FilterValue) {
400218887Sdim    assert(I < getNumFilters());
401218887Sdim    getFilters()[I] = FilterValue;
402218887Sdim  }
403218887Sdim
404218887Sdim  llvm::Value *getFilter(unsigned I) const {
405218887Sdim    assert(I < getNumFilters());
406218887Sdim    return getFilters()[I];
407218887Sdim  }
408218887Sdim
409218887Sdim  static bool classof(const EHScope *Scope) {
410218887Sdim    return Scope->getKind() == Filter;
411218887Sdim  }
412218887Sdim};
413218887Sdim
414218887Sdim/// An exceptions scope which calls std::terminate if any exception
415218887Sdim/// reaches it.
416218887Sdimclass EHTerminateScope : public EHScope {
417218887Sdim  unsigned DestIndex : BitsRemaining;
418218887Sdimpublic:
419218887Sdim  EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {}
420218887Sdim  static size_t getSize() { return sizeof(EHTerminateScope); }
421218887Sdim
422218887Sdim  unsigned getDestIndex() const { return DestIndex; }
423218887Sdim
424218887Sdim  static bool classof(const EHScope *Scope) {
425218887Sdim    return Scope->getKind() == Terminate;
426218887Sdim  }
427218887Sdim};
428218887Sdim
429218887Sdim/// A non-stable pointer into the scope stack.
430218887Sdimclass EHScopeStack::iterator {
431218887Sdim  char *Ptr;
432218887Sdim
433218887Sdim  friend class EHScopeStack;
434218887Sdim  explicit iterator(char *Ptr) : Ptr(Ptr) {}
435218887Sdim
436218887Sdimpublic:
437218887Sdim  iterator() : Ptr(0) {}
438218887Sdim
439218887Sdim  EHScope *get() const {
440218887Sdim    return reinterpret_cast<EHScope*>(Ptr);
441218887Sdim  }
442218887Sdim
443218887Sdim  EHScope *operator->() const { return get(); }
444218887Sdim  EHScope &operator*() const { return *get(); }
445218887Sdim
446218887Sdim  iterator &operator++() {
447218887Sdim    switch (get()->getKind()) {
448218887Sdim    case EHScope::Catch:
449218887Sdim      Ptr += EHCatchScope::getSizeForNumHandlers(
450218887Sdim          static_cast<const EHCatchScope*>(get())->getNumHandlers());
451218887Sdim      break;
452218887Sdim
453218887Sdim    case EHScope::Filter:
454218887Sdim      Ptr += EHFilterScope::getSizeForNumFilters(
455218887Sdim          static_cast<const EHFilterScope*>(get())->getNumFilters());
456218887Sdim      break;
457218887Sdim
458218887Sdim    case EHScope::Cleanup:
459218887Sdim      Ptr += static_cast<const EHCleanupScope*>(get())
460218887Sdim        ->getAllocatedSize();
461218887Sdim      break;
462218887Sdim
463218887Sdim    case EHScope::Terminate:
464218887Sdim      Ptr += EHTerminateScope::getSize();
465218887Sdim      break;
466218887Sdim    }
467218887Sdim
468218887Sdim    return *this;
469218887Sdim  }
470218887Sdim
471218887Sdim  iterator next() {
472218887Sdim    iterator copy = *this;
473218887Sdim    ++copy;
474218887Sdim    return copy;
475218887Sdim  }
476218887Sdim
477218887Sdim  iterator operator++(int) {
478218887Sdim    iterator copy = *this;
479218887Sdim    operator++();
480218887Sdim    return copy;
481218887Sdim  }
482218887Sdim
483218887Sdim  bool encloses(iterator other) const { return Ptr >= other.Ptr; }
484218887Sdim  bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
485218887Sdim
486218887Sdim  bool operator==(iterator other) const { return Ptr == other.Ptr; }
487218887Sdim  bool operator!=(iterator other) const { return Ptr != other.Ptr; }
488218887Sdim};
489218887Sdim
490218887Sdiminline EHScopeStack::iterator EHScopeStack::begin() const {
491218887Sdim  return iterator(StartOfData);
492218887Sdim}
493218887Sdim
494218887Sdiminline EHScopeStack::iterator EHScopeStack::end() const {
495218887Sdim  return iterator(EndOfBuffer);
496218887Sdim}
497218887Sdim
498218887Sdiminline void EHScopeStack::popCatch() {
499218887Sdim  assert(!empty() && "popping exception stack when not empty");
500218887Sdim
501218887Sdim  assert(isa<EHCatchScope>(*begin()));
502218887Sdim  StartOfData += EHCatchScope::getSizeForNumHandlers(
503218887Sdim                          cast<EHCatchScope>(*begin()).getNumHandlers());
504218887Sdim
505218887Sdim  if (empty()) NextEHDestIndex = FirstEHDestIndex;
506218887Sdim
507218887Sdim  assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
508218887Sdim  CatchDepth--;
509218887Sdim}
510218887Sdim
511218887Sdiminline void EHScopeStack::popTerminate() {
512218887Sdim  assert(!empty() && "popping exception stack when not empty");
513218887Sdim
514218887Sdim  assert(isa<EHTerminateScope>(*begin()));
515218887Sdim  StartOfData += EHTerminateScope::getSize();
516218887Sdim
517218887Sdim  if (empty()) NextEHDestIndex = FirstEHDestIndex;
518218887Sdim
519218887Sdim  assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
520218887Sdim  CatchDepth--;
521218887Sdim}
522218887Sdim
523218887Sdiminline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
524218887Sdim  assert(sp.isValid() && "finding invalid savepoint");
525218887Sdim  assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
526218887Sdim  return iterator(EndOfBuffer - sp.Size);
527218887Sdim}
528218887Sdim
529218887Sdiminline EHScopeStack::stable_iterator
530218887SdimEHScopeStack::stabilize(iterator ir) const {
531218887Sdim  assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
532218887Sdim  return stable_iterator(EndOfBuffer - ir.Ptr);
533218887Sdim}
534218887Sdim
535218887Sdiminline EHScopeStack::stable_iterator
536218887SdimEHScopeStack::getInnermostActiveNormalCleanup() const {
537218887Sdim  for (EHScopeStack::stable_iterator
538218887Sdim         I = getInnermostNormalCleanup(), E = stable_end(); I != E; ) {
539218887Sdim    EHCleanupScope &S = cast<EHCleanupScope>(*find(I));
540218887Sdim    if (S.isActive()) return I;
541218887Sdim    I = S.getEnclosingNormalCleanup();
542218887Sdim  }
543218887Sdim  return stable_end();
544218887Sdim}
545218887Sdim
546218887Sdiminline EHScopeStack::stable_iterator
547218887SdimEHScopeStack::getInnermostActiveEHCleanup() const {
548218887Sdim  for (EHScopeStack::stable_iterator
549218887Sdim         I = getInnermostEHCleanup(), E = stable_end(); I != E; ) {
550218887Sdim    EHCleanupScope &S = cast<EHCleanupScope>(*find(I));
551218887Sdim    if (S.isActive()) return I;
552218887Sdim    I = S.getEnclosingEHCleanup();
553218887Sdim  }
554218887Sdim  return stable_end();
555218887Sdim}
556218887Sdim
557218887Sdim}
558218887Sdim}
559218887Sdim
560218887Sdim#endif
561