1226586Sdim//===--- VTableBuilder.h - C++ vtable layout builder --------------*- C++ -*-=//
2226586Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6226586Sdim//
7226586Sdim//===----------------------------------------------------------------------===//
8226586Sdim//
9226586Sdim// This contains code dealing with generation of the layout of virtual tables.
10226586Sdim//
11226586Sdim//===----------------------------------------------------------------------===//
12226586Sdim
13226586Sdim#ifndef LLVM_CLANG_AST_VTABLEBUILDER_H
14226586Sdim#define LLVM_CLANG_AST_VTABLEBUILDER_H
15226586Sdim
16226586Sdim#include "clang/AST/BaseSubobject.h"
17226586Sdim#include "clang/AST/CXXInheritance.h"
18226586Sdim#include "clang/AST/GlobalDecl.h"
19226586Sdim#include "clang/AST/RecordLayout.h"
20226586Sdim#include "clang/Basic/ABI.h"
21276479Sdim#include "llvm/ADT/DenseMap.h"
22276479Sdim#include <memory>
23226586Sdim#include <utility>
24226586Sdim
25226586Sdimnamespace clang {
26226586Sdim  class CXXRecordDecl;
27226586Sdim
28341825Sdim/// Represents a single component in a vtable.
29226586Sdimclass VTableComponent {
30226586Sdimpublic:
31226586Sdim  enum Kind {
32226586Sdim    CK_VCallOffset,
33226586Sdim    CK_VBaseOffset,
34226586Sdim    CK_OffsetToTop,
35226586Sdim    CK_RTTI,
36226586Sdim    CK_FunctionPointer,
37234353Sdim
38341825Sdim    /// A pointer to the complete destructor.
39226586Sdim    CK_CompleteDtorPointer,
40234353Sdim
41341825Sdim    /// A pointer to the deleting destructor.
42226586Sdim    CK_DeletingDtorPointer,
43234353Sdim
44341825Sdim    /// An entry that is never used.
45261991Sdim    ///
46261991Sdim    /// In some cases, a vtable function pointer will end up never being
47261991Sdim    /// called. Such vtable function pointers are represented as a
48261991Sdim    /// CK_UnusedFunctionPointer.
49226586Sdim    CK_UnusedFunctionPointer
50226586Sdim  };
51226586Sdim
52296417Sdim  VTableComponent() = default;
53226586Sdim
54226586Sdim  static VTableComponent MakeVCallOffset(CharUnits Offset) {
55226586Sdim    return VTableComponent(CK_VCallOffset, Offset);
56226586Sdim  }
57226586Sdim
58226586Sdim  static VTableComponent MakeVBaseOffset(CharUnits Offset) {
59226586Sdim    return VTableComponent(CK_VBaseOffset, Offset);
60226586Sdim  }
61226586Sdim
62226586Sdim  static VTableComponent MakeOffsetToTop(CharUnits Offset) {
63226586Sdim    return VTableComponent(CK_OffsetToTop, Offset);
64226586Sdim  }
65234353Sdim
66226586Sdim  static VTableComponent MakeRTTI(const CXXRecordDecl *RD) {
67226586Sdim    return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
68226586Sdim  }
69226586Sdim
70226586Sdim  static VTableComponent MakeFunction(const CXXMethodDecl *MD) {
71234353Sdim    assert(!isa<CXXDestructorDecl>(MD) &&
72226586Sdim           "Don't use MakeFunction with destructors!");
73226586Sdim
74234353Sdim    return VTableComponent(CK_FunctionPointer,
75226586Sdim                           reinterpret_cast<uintptr_t>(MD));
76226586Sdim  }
77234353Sdim
78226586Sdim  static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
79226586Sdim    return VTableComponent(CK_CompleteDtorPointer,
80226586Sdim                           reinterpret_cast<uintptr_t>(DD));
81226586Sdim  }
82226586Sdim
83226586Sdim  static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
84234353Sdim    return VTableComponent(CK_DeletingDtorPointer,
85226586Sdim                           reinterpret_cast<uintptr_t>(DD));
86226586Sdim  }
87226586Sdim
88226586Sdim  static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
89234353Sdim    assert(!isa<CXXDestructorDecl>(MD) &&
90226586Sdim           "Don't use MakeUnusedFunction with destructors!");
91226586Sdim    return VTableComponent(CK_UnusedFunctionPointer,
92234353Sdim                           reinterpret_cast<uintptr_t>(MD));
93226586Sdim  }
94226586Sdim
95341825Sdim  /// Get the kind of this vtable component.
96226586Sdim  Kind getKind() const {
97226586Sdim    return (Kind)(Value & 0x7);
98226586Sdim  }
99226586Sdim
100226586Sdim  CharUnits getVCallOffset() const {
101226586Sdim    assert(getKind() == CK_VCallOffset && "Invalid component kind!");
102234353Sdim
103226586Sdim    return getOffset();
104226586Sdim  }
105226586Sdim
106226586Sdim  CharUnits getVBaseOffset() const {
107226586Sdim    assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
108234353Sdim
109226586Sdim    return getOffset();
110226586Sdim  }
111226586Sdim
112226586Sdim  CharUnits getOffsetToTop() const {
113226586Sdim    assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
114234353Sdim
115226586Sdim    return getOffset();
116226586Sdim  }
117234353Sdim
118226586Sdim  const CXXRecordDecl *getRTTIDecl() const {
119296417Sdim    assert(isRTTIKind() && "Invalid component kind!");
120226586Sdim    return reinterpret_cast<CXXRecordDecl *>(getPointer());
121226586Sdim  }
122234353Sdim
123226586Sdim  const CXXMethodDecl *getFunctionDecl() const {
124296417Sdim    assert(isFunctionPointerKind() && "Invalid component kind!");
125296417Sdim    if (isDestructorKind())
126296417Sdim      return getDestructorDecl();
127226586Sdim    return reinterpret_cast<CXXMethodDecl *>(getPointer());
128226586Sdim  }
129226586Sdim
130226586Sdim  const CXXDestructorDecl *getDestructorDecl() const {
131296417Sdim    assert(isDestructorKind() && "Invalid component kind!");
132226586Sdim    return reinterpret_cast<CXXDestructorDecl *>(getPointer());
133226586Sdim  }
134226586Sdim
135226586Sdim  const CXXMethodDecl *getUnusedFunctionDecl() const {
136296417Sdim    assert(getKind() == CK_UnusedFunctionPointer && "Invalid component kind!");
137226586Sdim    return reinterpret_cast<CXXMethodDecl *>(getPointer());
138226586Sdim  }
139234353Sdim
140296417Sdim  bool isDestructorKind() const { return isDestructorKind(getKind()); }
141296417Sdim
142296417Sdim  bool isUsedFunctionPointerKind() const {
143296417Sdim    return isUsedFunctionPointerKind(getKind());
144296417Sdim  }
145296417Sdim
146296417Sdim  bool isFunctionPointerKind() const {
147296417Sdim    return isFunctionPointerKind(getKind());
148296417Sdim  }
149296417Sdim
150296417Sdim  bool isRTTIKind() const { return isRTTIKind(getKind()); }
151296417Sdim
152321369Sdim  GlobalDecl getGlobalDecl() const {
153321369Sdim    assert(isUsedFunctionPointerKind() &&
154321369Sdim           "GlobalDecl can be created only from virtual function");
155321369Sdim
156321369Sdim    auto *DtorDecl = dyn_cast<CXXDestructorDecl>(getFunctionDecl());
157321369Sdim    switch (getKind()) {
158321369Sdim    case CK_FunctionPointer:
159321369Sdim      return GlobalDecl(getFunctionDecl());
160321369Sdim    case CK_CompleteDtorPointer:
161321369Sdim      return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Complete);
162321369Sdim    case CK_DeletingDtorPointer:
163321369Sdim      return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Deleting);
164321369Sdim    case CK_VCallOffset:
165321369Sdim    case CK_VBaseOffset:
166321369Sdim    case CK_OffsetToTop:
167321369Sdim    case CK_RTTI:
168321369Sdim    case CK_UnusedFunctionPointer:
169321369Sdim      llvm_unreachable("Only function pointers kinds");
170321369Sdim    }
171321369Sdim    llvm_unreachable("Should already return");
172321369Sdim  }
173321369Sdim
174226586Sdimprivate:
175296417Sdim  static bool isFunctionPointerKind(Kind ComponentKind) {
176296417Sdim    return isUsedFunctionPointerKind(ComponentKind) ||
177296417Sdim           ComponentKind == CK_UnusedFunctionPointer;
178296417Sdim  }
179296417Sdim  static bool isUsedFunctionPointerKind(Kind ComponentKind) {
180296417Sdim    return ComponentKind == CK_FunctionPointer ||
181296417Sdim           isDestructorKind(ComponentKind);
182296417Sdim  }
183296417Sdim  static bool isDestructorKind(Kind ComponentKind) {
184296417Sdim    return ComponentKind == CK_CompleteDtorPointer ||
185296417Sdim           ComponentKind == CK_DeletingDtorPointer;
186296417Sdim  }
187296417Sdim  static bool isRTTIKind(Kind ComponentKind) {
188296417Sdim    return ComponentKind == CK_RTTI;
189296417Sdim  }
190296417Sdim
191226586Sdim  VTableComponent(Kind ComponentKind, CharUnits Offset) {
192234353Sdim    assert((ComponentKind == CK_VCallOffset ||
193226586Sdim            ComponentKind == CK_VBaseOffset ||
194226586Sdim            ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
195243830Sdim    assert(Offset.getQuantity() < (1LL << 56) && "Offset is too big!");
196243830Sdim    assert(Offset.getQuantity() >= -(1LL << 56) && "Offset is too small!");
197234353Sdim
198243830Sdim    Value = (uint64_t(Offset.getQuantity()) << 3) | ComponentKind;
199226586Sdim  }
200226586Sdim
201226586Sdim  VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
202296417Sdim    assert((isRTTIKind(ComponentKind) || isFunctionPointerKind(ComponentKind)) &&
203296417Sdim           "Invalid component kind!");
204234353Sdim
205226586Sdim    assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
206234353Sdim
207226586Sdim    Value = Ptr | ComponentKind;
208226586Sdim  }
209234353Sdim
210226586Sdim  CharUnits getOffset() const {
211226586Sdim    assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
212226586Sdim            getKind() == CK_OffsetToTop) && "Invalid component kind!");
213234353Sdim
214226586Sdim    return CharUnits::fromQuantity(Value >> 3);
215226586Sdim  }
216226586Sdim
217226586Sdim  uintptr_t getPointer() const {
218296417Sdim    assert((getKind() == CK_RTTI || isFunctionPointerKind()) &&
219226586Sdim           "Invalid component kind!");
220234353Sdim
221226586Sdim    return static_cast<uintptr_t>(Value & ~7ULL);
222226586Sdim  }
223234353Sdim
224226586Sdim  /// The kind is stored in the lower 3 bits of the value. For offsets, we
225226586Sdim  /// make use of the facts that classes can't be larger than 2^55 bytes,
226261991Sdim  /// so we store the offset in the lower part of the 61 bits that remain.
227226586Sdim  /// (The reason that we're not simply using a PointerIntPair here is that we
228226586Sdim  /// need the offsets to be 64-bit, even when on a 32-bit machine).
229226586Sdim  int64_t Value;
230226586Sdim};
231226586Sdim
232226586Sdimclass VTableLayout {
233226586Sdimpublic:
234226586Sdim  typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy;
235314564Sdim  struct AddressPointLocation {
236314564Sdim    unsigned VTableIndex, AddressPointIndex;
237314564Sdim  };
238314564Sdim  typedef llvm::DenseMap<BaseSubobject, AddressPointLocation>
239314564Sdim      AddressPointsMapTy;
240226586Sdim
241314564Sdimprivate:
242314564Sdim  // Stores the component indices of the first component of each virtual table in
243314564Sdim  // the virtual table group. To save a little memory in the common case where
244314564Sdim  // the vtable group contains a single vtable, an empty vector here represents
245314564Sdim  // the vector {0}.
246314564Sdim  OwningArrayRef<size_t> VTableIndices;
247226586Sdim
248314564Sdim  OwningArrayRef<VTableComponent> VTableComponents;
249296417Sdim
250341825Sdim  /// Contains thunks needed by vtables, sorted by indices.
251314564Sdim  OwningArrayRef<VTableThunkTy> VTableThunks;
252234353Sdim
253341825Sdim  /// Address points for all vtables.
254226586Sdim  AddressPointsMapTy AddressPoints;
255226586Sdim
256226586Sdimpublic:
257314564Sdim  VTableLayout(ArrayRef<size_t> VTableIndices,
258314564Sdim               ArrayRef<VTableComponent> VTableComponents,
259314564Sdim               ArrayRef<VTableThunkTy> VTableThunks,
260314564Sdim               const AddressPointsMapTy &AddressPoints);
261226586Sdim  ~VTableLayout();
262226586Sdim
263314564Sdim  ArrayRef<VTableComponent> vtable_components() const {
264314564Sdim    return VTableComponents;
265226586Sdim  }
266226586Sdim
267314564Sdim  ArrayRef<VTableThunkTy> vtable_thunks() const {
268314564Sdim    return VTableThunks;
269296417Sdim  }
270296417Sdim
271314564Sdim  AddressPointLocation getAddressPoint(BaseSubobject Base) const {
272314564Sdim    assert(AddressPoints.count(Base) && "Did not find address point!");
273314564Sdim    return AddressPoints.find(Base)->second;
274226586Sdim  }
275226586Sdim
276314564Sdim  const AddressPointsMapTy &getAddressPoints() const {
277314564Sdim    return AddressPoints;
278226586Sdim  }
279226586Sdim
280314564Sdim  size_t getNumVTables() const {
281314564Sdim    if (VTableIndices.empty())
282314564Sdim      return 1;
283314564Sdim    return VTableIndices.size();
284226586Sdim  }
285226586Sdim
286314564Sdim  size_t getVTableOffset(size_t i) const {
287314564Sdim    if (VTableIndices.empty()) {
288314564Sdim      assert(i == 0);
289314564Sdim      return 0;
290314564Sdim    }
291314564Sdim    return VTableIndices[i];
292226586Sdim  }
293226586Sdim
294314564Sdim  size_t getVTableSize(size_t i) const {
295314564Sdim    if (VTableIndices.empty()) {
296314564Sdim      assert(i == 0);
297314564Sdim      return vtable_components().size();
298314564Sdim    }
299226586Sdim
300314564Sdim    size_t thisIndex = VTableIndices[i];
301314564Sdim    size_t nextIndex = (i + 1 == VTableIndices.size())
302314564Sdim                           ? vtable_components().size()
303314564Sdim                           : VTableIndices[i + 1];
304314564Sdim    return nextIndex - thisIndex;
305226586Sdim  }
306226586Sdim};
307226586Sdim
308261991Sdimclass VTableContextBase {
309226586Sdimpublic:
310226586Sdim  typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
311234353Sdim
312276479Sdim  bool isMicrosoft() const { return IsMicrosoftABI; }
313276479Sdim
314276479Sdim  virtual ~VTableContextBase() {}
315276479Sdim
316261991Sdimprotected:
317261991Sdim  typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
318261991Sdim
319341825Sdim  /// Contains all thunks that a given method decl will need.
320261991Sdim  ThunksMapTy Thunks;
321261991Sdim
322261991Sdim  /// Compute and store all vtable related information (vtable layout, vbase
323261991Sdim  /// offset offsets, thunks etc) for the given record decl.
324261991Sdim  virtual void computeVTableRelatedInformation(const CXXRecordDecl *RD) = 0;
325261991Sdim
326276479Sdim  VTableContextBase(bool MS) : IsMicrosoftABI(MS) {}
327261991Sdim
328261991Sdimpublic:
329261991Sdim  virtual const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) {
330261991Sdim    const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()->getCanonicalDecl());
331261991Sdim    computeVTableRelatedInformation(MD->getParent());
332261991Sdim
333261991Sdim    // This assumes that all the destructors present in the vtable
334261991Sdim    // use exactly the same set of thunks.
335261991Sdim    ThunksMapTy::const_iterator I = Thunks.find(MD);
336261991Sdim    if (I == Thunks.end()) {
337261991Sdim      // We did not find a thunk for this method.
338276479Sdim      return nullptr;
339261991Sdim    }
340261991Sdim
341261991Sdim    return &I->second;
342261991Sdim  }
343276479Sdim
344276479Sdim  bool IsMicrosoftABI;
345261991Sdim};
346261991Sdim
347261991Sdimclass ItaniumVTableContext : public VTableContextBase {
348226586Sdimprivate:
349249423Sdim
350341825Sdim  /// Contains the index (relative to the vtable address point)
351261991Sdim  /// where the function pointer for a virtual function is stored.
352226586Sdim  typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
353226586Sdim  MethodVTableIndicesTy MethodVTableIndices;
354226586Sdim
355314564Sdim  typedef llvm::DenseMap<const CXXRecordDecl *,
356314564Sdim                         std::unique_ptr<const VTableLayout>>
357314564Sdim      VTableLayoutMapTy;
358226586Sdim  VTableLayoutMapTy VTableLayouts;
359226586Sdim
360226586Sdim  typedef std::pair<const CXXRecordDecl *,
361226586Sdim                    const CXXRecordDecl *> ClassPairTy;
362226586Sdim
363341825Sdim  /// vtable offsets for offsets of virtual bases of a class.
364261991Sdim  ///
365261991Sdim  /// Contains the vtable offset (relative to the address point) in chars
366261991Sdim  /// where the offsets for virtual bases of a class are stored.
367234353Sdim  typedef llvm::DenseMap<ClassPairTy, CharUnits>
368226586Sdim    VirtualBaseClassOffsetOffsetsMapTy;
369226586Sdim  VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
370226586Sdim
371276479Sdim  void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;
372234353Sdim
373226586Sdimpublic:
374261991Sdim  ItaniumVTableContext(ASTContext &Context);
375288943Sdim  ~ItaniumVTableContext() override;
376226586Sdim
377226586Sdim  const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
378261991Sdim    computeVTableRelatedInformation(RD);
379226586Sdim    assert(VTableLayouts.count(RD) && "No layout for this record decl!");
380234353Sdim
381226586Sdim    return *VTableLayouts[RD];
382226586Sdim  }
383226586Sdim
384314564Sdim  std::unique_ptr<VTableLayout> createConstructionVTableLayout(
385314564Sdim      const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset,
386314564Sdim      bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass);
387226586Sdim
388341825Sdim  /// Locate a virtual function in the vtable.
389261991Sdim  ///
390261991Sdim  /// Return the index (relative to the vtable address point) where the
391261991Sdim  /// function pointer for the given virtual function is stored.
392261991Sdim  uint64_t getMethodVTableIndex(GlobalDecl GD);
393226586Sdim
394261991Sdim  /// Return the offset in chars (relative to the vtable address point) where
395261991Sdim  /// the offset of the virtual base that contains the given base is stored,
396341825Sdim  /// otherwise, if no virtual base contains the given class, return 0.
397261991Sdim  ///
398261991Sdim  /// Base must be a virtual base class or an unambiguous base.
399261991Sdim  CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
400261991Sdim                                       const CXXRecordDecl *VBase);
401276479Sdim
402276479Sdim  static bool classof(const VTableContextBase *VT) {
403276479Sdim    return !VT->isMicrosoft();
404276479Sdim  }
405261991Sdim};
406226586Sdim
407276479Sdim/// Holds information about the inheritance path to a virtual base or function
408276479Sdim/// table pointer.  A record may contain as many vfptrs or vbptrs as there are
409276479Sdim/// base subobjects.
410276479Sdimstruct VPtrInfo {
411261991Sdim  typedef SmallVector<const CXXRecordDecl *, 1> BasePath;
412261991Sdim
413276479Sdim  VPtrInfo(const CXXRecordDecl *RD)
414314564Sdim      : ObjectWithVPtr(RD), IntroducingObject(RD), NextBaseToMangle(RD) {}
415226586Sdim
416314564Sdim  /// This is the most derived class that has this vptr at offset zero. When
417314564Sdim  /// single inheritance is used, this is always the most derived class. If
418314564Sdim  /// multiple inheritance is used, it may be any direct or indirect base.
419314564Sdim  const CXXRecordDecl *ObjectWithVPtr;
420226586Sdim
421314564Sdim  /// This is the class that introduced the vptr by declaring new virtual
422314564Sdim  /// methods or virtual bases.
423314564Sdim  const CXXRecordDecl *IntroducingObject;
424314564Sdim
425314564Sdim  /// IntroducingObject is at this offset from its containing complete object or
426276479Sdim  /// virtual base.
427276479Sdim  CharUnits NonVirtualOffset;
428261991Sdim
429276479Sdim  /// The bases from the inheritance path that got used to mangle the vbtable
430276479Sdim  /// name.  This is not really a full path like a CXXBasePath.  It holds the
431276479Sdim  /// subset of records that need to be mangled into the vbtable symbol name in
432276479Sdim  /// order to get a unique name.
433276479Sdim  BasePath MangledPath;
434276479Sdim
435276479Sdim  /// The next base to push onto the mangled path if this path is ambiguous in a
436276479Sdim  /// derived class.  If it's null, then it's already been pushed onto the path.
437276479Sdim  const CXXRecordDecl *NextBaseToMangle;
438276479Sdim
439276479Sdim  /// The set of possibly indirect vbases that contain this vbtable.  When a
440276479Sdim  /// derived class indirectly inherits from the same vbase twice, we only keep
441276479Sdim  /// vtables and their paths from the first instance.
442276479Sdim  BasePath ContainingVBases;
443276479Sdim
444261991Sdim  /// This holds the base classes path from the complete type to the first base
445276479Sdim  /// with the given vfptr offset, in the base-to-derived order.  Only used for
446276479Sdim  /// vftables.
447314564Sdim  BasePath PathToIntroducingObject;
448261991Sdim
449276479Sdim  /// Static offset from the top of the most derived class to this vfptr,
450276479Sdim  /// including any virtual base offset.  Only used for vftables.
451276479Sdim  CharUnits FullOffsetInMDC;
452261991Sdim
453276479Sdim  /// The vptr is stored inside the non-virtual component of this virtual base.
454276479Sdim  const CXXRecordDecl *getVBaseWithVPtr() const {
455276479Sdim    return ContainingVBases.empty() ? nullptr : ContainingVBases.front();
456276479Sdim  }
457226586Sdim};
458226586Sdim
459314564Sdimtypedef SmallVector<std::unique_ptr<VPtrInfo>, 2> VPtrInfoVector;
460276479Sdim
461276479Sdim/// All virtual base related information about a given record decl.  Includes
462276479Sdim/// information on all virtual base tables and the path components that are used
463276479Sdim/// to mangle them.
464276479Sdimstruct VirtualBaseInfo {
465276479Sdim  /// A map from virtual base to vbtable index for doing a conversion from the
466276479Sdim  /// the derived class to the a base.
467276479Sdim  llvm::DenseMap<const CXXRecordDecl *, unsigned> VBTableIndices;
468276479Sdim
469276479Sdim  /// Information on all virtual base tables used when this record is the most
470276479Sdim  /// derived class.
471276479Sdim  VPtrInfoVector VBPtrPaths;
472276479Sdim};
473276479Sdim
474341825Sdimstruct MethodVFTableLocation {
475341825Sdim  /// If nonzero, holds the vbtable index of the virtual base with the vfptr.
476341825Sdim  uint64_t VBTableIndex;
477261991Sdim
478341825Sdim  /// If nonnull, holds the last vbase which contains the vfptr that the
479341825Sdim  /// method definition is adjusted to.
480341825Sdim  const CXXRecordDecl *VBase;
481261991Sdim
482341825Sdim  /// This is the offset of the vfptr from the start of the last vbase, or the
483341825Sdim  /// complete type if there are no virtual bases.
484341825Sdim  CharUnits VFPtrOffset;
485261991Sdim
486341825Sdim  /// Method's index in the vftable.
487341825Sdim  uint64_t Index;
488261991Sdim
489341825Sdim  MethodVFTableLocation()
490341825Sdim      : VBTableIndex(0), VBase(nullptr), VFPtrOffset(CharUnits::Zero()),
491341825Sdim        Index(0) {}
492261991Sdim
493341825Sdim  MethodVFTableLocation(uint64_t VBTableIndex, const CXXRecordDecl *VBase,
494341825Sdim                        CharUnits VFPtrOffset, uint64_t Index)
495341825Sdim      : VBTableIndex(VBTableIndex), VBase(VBase), VFPtrOffset(VFPtrOffset),
496341825Sdim        Index(Index) {}
497261991Sdim
498341825Sdim  bool operator<(const MethodVFTableLocation &other) const {
499341825Sdim    if (VBTableIndex != other.VBTableIndex) {
500341825Sdim      assert(VBase != other.VBase);
501341825Sdim      return VBTableIndex < other.VBTableIndex;
502261991Sdim    }
503341825Sdim    return std::tie(VFPtrOffset, Index) <
504341825Sdim           std::tie(other.VFPtrOffset, other.Index);
505341825Sdim  }
506341825Sdim};
507261991Sdim
508341825Sdimclass MicrosoftVTableContext : public VTableContextBase {
509341825Sdimpublic:
510341825Sdim
511261991Sdimprivate:
512261991Sdim  ASTContext &Context;
513261991Sdim
514261991Sdim  typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
515261991Sdim    MethodVFTableLocationsTy;
516261991Sdim  MethodVFTableLocationsTy MethodVFTableLocations;
517261991Sdim
518341825Sdim  typedef llvm::DenseMap<const CXXRecordDecl *, std::unique_ptr<VPtrInfoVector>>
519314564Sdim      VFPtrLocationsMapTy;
520261991Sdim  VFPtrLocationsMapTy VFPtrLocations;
521261991Sdim
522261991Sdim  typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
523314564Sdim  typedef llvm::DenseMap<VFTableIdTy, std::unique_ptr<const VTableLayout>>
524314564Sdim      VFTableLayoutMapTy;
525261991Sdim  VFTableLayoutMapTy VFTableLayouts;
526261991Sdim
527314564Sdim  llvm::DenseMap<const CXXRecordDecl *, std::unique_ptr<VirtualBaseInfo>>
528314564Sdim      VBaseInfo;
529261991Sdim
530276479Sdim  void enumerateVFPtrs(const CXXRecordDecl *ForClass, VPtrInfoVector &Result);
531261991Sdim
532276479Sdim  void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;
533261991Sdim
534261991Sdim  void dumpMethodLocations(const CXXRecordDecl *RD,
535261991Sdim                           const MethodVFTableLocationsTy &NewMethods,
536261991Sdim                           raw_ostream &);
537261991Sdim
538314564Sdim  const VirtualBaseInfo &
539276479Sdim  computeVBTableRelatedInformation(const CXXRecordDecl *RD);
540261991Sdim
541276479Sdim  void computeVTablePaths(bool ForVBTables, const CXXRecordDecl *RD,
542276479Sdim                          VPtrInfoVector &Paths);
543261991Sdim
544261991Sdimpublic:
545276479Sdim  MicrosoftVTableContext(ASTContext &Context)
546276479Sdim      : VTableContextBase(/*MS=*/true), Context(Context) {}
547261991Sdim
548288943Sdim  ~MicrosoftVTableContext() override;
549261991Sdim
550276479Sdim  const VPtrInfoVector &getVFPtrOffsets(const CXXRecordDecl *RD);
551261991Sdim
552261991Sdim  const VTableLayout &getVFTableLayout(const CXXRecordDecl *RD,
553261991Sdim                                       CharUnits VFPtrOffset);
554261991Sdim
555341825Sdim  MethodVFTableLocation getMethodVFTableLocation(GlobalDecl GD);
556261991Sdim
557276479Sdim  const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) override {
558261991Sdim    // Complete destructors don't have a slot in a vftable, so no thunks needed.
559261991Sdim    if (isa<CXXDestructorDecl>(GD.getDecl()) &&
560261991Sdim        GD.getDtorType() == Dtor_Complete)
561276479Sdim      return nullptr;
562261991Sdim    return VTableContextBase::getThunkInfo(GD);
563261991Sdim  }
564261991Sdim
565341825Sdim  /// Returns the index of VBase in the vbtable of Derived.
566261991Sdim  /// VBase must be a morally virtual base of Derived.
567261991Sdim  /// The vbtable is an array of i32 offsets.  The first entry is a self entry,
568261991Sdim  /// and the rest are offsets from the vbptr to virtual bases.
569261991Sdim  unsigned getVBTableIndex(const CXXRecordDecl *Derived,
570276479Sdim                           const CXXRecordDecl *VBase);
571276479Sdim
572276479Sdim  const VPtrInfoVector &enumerateVBTables(const CXXRecordDecl *RD);
573276479Sdim
574276479Sdim  static bool classof(const VTableContextBase *VT) { return VT->isMicrosoft(); }
575261991Sdim};
576226586Sdim
577276479Sdim} // namespace clang
578276479Sdim
579226586Sdim#endif
580