1e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka//===--- VTTBuilder.cpp - C++ VTT layout builder --------------------------===//
2e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka//
3e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka//                     The LLVM Compiler Infrastructure
4e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka//
5e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka// This file is distributed under the University of Illinois Open Source
6e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka// License. See LICENSE.TXT for details.
7e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka//
8e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka//===----------------------------------------------------------------------===//
9e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka//
10e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka// This contains code dealing with generation of the layout of virtual table
11e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka// tables (VTT).
12e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka//
13e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka//===----------------------------------------------------------------------===//
14e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
15e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka#include "clang/AST/VTTBuilder.h"
16e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka#include "clang/AST/ASTContext.h"
17d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenka#include "clang/AST/CXXInheritance.h"
18e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka#include "clang/AST/RecordLayout.h"
19e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka#include "clang/Basic/TargetInfo.h"
20e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka#include "llvm/Support/Format.h"
21e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka#include <algorithm>
22e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka#include <cstdio>
23e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
24e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkausing namespace clang;
25b93bb3538c55f173f94a4ee7510d9d1521d8f731Shishir Agrawal
26c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal#define DUMP_OVERRIDERS 0
274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
28e287feac673ff68565b766e0e463d105fa9cef9dAlex YakavenkaVTTBuilder::VTTBuilder(ASTContext &Ctx,
29e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                       const CXXRecordDecl *MostDerivedClass,
30e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                       bool GenerateDefinition)
31e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  : Ctx(Ctx), MostDerivedClass(MostDerivedClass),
32e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)),
33e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    GenerateDefinition(GenerateDefinition) {
34e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  // Lay out this VTT.
35b93bb3538c55f173f94a4ee7510d9d1521d8f731Shishir Agrawal  LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
36ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            /*BaseIsVirtual=*/false);
374baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal}
38b93bb3538c55f173f94a4ee7510d9d1521d8f731Shishir Agrawal
39e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkavoid VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
40e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                  const CXXRecordDecl *VTableClass) {
41d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenka  // Store the vtable pointer index if we're generating the primary VTT.
42e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  if (VTableClass == MostDerivedClass) {
43e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    assert(!SecondaryVirtualPointerIndices.count(Base) &&
44e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka           "A virtual pointer index already exists for this base subobject!");
45e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
46d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenka  }
47d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenka
48d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenka  if (!GenerateDefinition) {
49e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    VTTComponents.push_back(VTTComponent());
50e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    return;
51e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  }
52e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
53e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  VTTComponents.push_back(VTTComponent(VTableIndex, Base));
54e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka}
55e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
56e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkavoid VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
57e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  const CXXRecordDecl *RD = Base.getBase();
5805ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka
5905ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka  for (const auto &I : RD->bases()) {
607f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal    // Don't layout virtual bases.
6105ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka    if (I.isVirtual())
62e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        continue;
63e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
64e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    const CXXRecordDecl *BaseDecl =
65e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka      cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
66cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville
67e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
68e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    CharUnits BaseOffset = Base.getBaseOffset() +
69b93bb3538c55f173f94a4ee7510d9d1521d8f731Shishir Agrawal      Layout.getBaseClassOffset(BaseDecl);
70b93bb3538c55f173f94a4ee7510d9d1521d8f731Shishir Agrawal
71e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    // Layout the VTT for this base.
72e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
73e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  }
74e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka}
75e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
76e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkavoid
77e287feac673ff68565b766e0e463d105fa9cef9dAlex YakavenkaVTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
78e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                           bool BaseIsMorallyVirtual,
79e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                           uint64_t VTableIndex,
80e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                           const CXXRecordDecl *VTableClass,
81e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                           VisitedVirtualBasesSetTy &VBases) {
82e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  const CXXRecordDecl *RD = Base.getBase();
83e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
844baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal  // We're not interested in bases that don't have virtual bases, and not
85e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  // morally virtual bases.
86e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
87c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    return;
88e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
89e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  for (const auto &I : RD->bases()) {
90e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    const CXXRecordDecl *BaseDecl =
91300cc7bd83f881abd0653a42f975223e0ab60cd4Shishir Agrawal      cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
92300cc7bd83f881abd0653a42f975223e0ab60cd4Shishir Agrawal
93e3ea8115b0d558f6c6b57b201885948f4309e5c0Shishir Agrawal    // Itanium C++ ABI 2.6.2:
94e3ea8115b0d558f6c6b57b201885948f4309e5c0Shishir Agrawal    //   Secondary virtual pointers are present for all bases with either
95e3ea8115b0d558f6c6b57b201885948f4309e5c0Shishir Agrawal    //   virtual bases or virtual function declarations overridden along a
96c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    //   virtual path.
97e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    //
98a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    // If the base class is not dynamic, we don't want to add it, nor any
99a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    // of its base classes.
100e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    if (!BaseDecl->isDynamicClass())
101e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka      continue;
102e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
103e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
104e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    bool BaseDeclIsNonVirtualPrimaryBase = false;
105e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    CharUnits BaseOffset;
106a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    if (I.isVirtual()) {
107a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville      // Ignore virtual bases that we've already visited.
108a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville      if (!VBases.insert(BaseDecl))
109a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        continue;
110a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
111a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville      BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
112a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville      BaseDeclIsMorallyVirtual = true;
113a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    } else {
114a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville      const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
115e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
116e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka      BaseOffset = Base.getBaseOffset() +
117e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        Layout.getBaseClassOffset(BaseDecl);
118e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
119e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka      if (!Layout.isPrimaryBaseVirtual() &&
120e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka          Layout.getPrimaryBase() == BaseDecl)
121e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        BaseDeclIsNonVirtualPrimaryBase = true;
122e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
123e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
124e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    // Itanium C++ ABI 2.6.2:
125e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    //   Secondary virtual pointers: for each base class X which (a) has virtual
1264baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    //   bases or is reachable along a virtual path from D, and (b) is not a
127e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    //   non-virtual primary base, the address of the virtual table for X-in-D
128e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    //   or an appropriate construction virtual table.
129e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    if (!BaseDeclIsNonVirtualPrimaryBase &&
130e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
131e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka      // Add the vtable pointer.
132e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka      AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex,
133e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                       VTableClass);
134e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
135e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
136e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    // And lay out the secondary virtual pointers for the base class.
137e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
138e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                   BaseDeclIsMorallyVirtual, VTableIndex,
139e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                   VTableClass, VBases);
140e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  }
141e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka}
142e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
143e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkavoid
144e287feac673ff68565b766e0e463d105fa9cef9dAlex YakavenkaVTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
145e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                           uint64_t VTableIndex) {
146e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  VisitedVirtualBasesSetTy VBases;
147e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
148e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                 VTableIndex, Base.getBase(), VBases);
149e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka}
150e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
151e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkavoid VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
152e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                   VisitedVirtualBasesSetTy &VBases) {
153e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  for (const auto &I : RD->bases()) {
154e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    const CXXRecordDecl *BaseDecl =
155e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka      cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
156e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
157e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    // Check if this is a virtual base.
158e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    if (I.isVirtual()) {
159e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka      // Check if we've seen this base before.
160e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka      if (!VBases.insert(BaseDecl))
161e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        continue;
162e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
163a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville      CharUnits BaseOffset =
1644baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
1654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1664baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal      LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
1674baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
168c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal
169c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    // We only need to layout virtual VTTs for this base if it actually has
1704baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // virtual bases.
1714baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    if (BaseDecl->getNumVBases())
1724baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal      LayoutVirtualVTTs(BaseDecl, VBases);
1734baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal  }
174e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka}
175e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
176e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkavoid VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
177e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  const CXXRecordDecl *RD = Base.getBase();
178e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
179e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  // Itanium C++ ABI 2.6.2:
180e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  //   An array of virtual table addresses, called the VTT, is declared for
181e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  //   each class type that has indirect or direct virtual base classes.
182e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  if (RD->getNumVBases() == 0)
183e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    return;
184e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
185e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
186e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
187e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  if (!IsPrimaryVTT) {
188e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    // Remember the sub-VTT index.
189e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    SubVTTIndicies[Base] = VTTComponents.size();
190e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  }
191e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
192e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  uint64_t VTableIndex = VTTVTables.size();
193e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual));
194e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
195e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka  // Add the primary vtable pointer.
196a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville  AddVTablePointer(Base, VTableIndex, RD);
197a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
198a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville  // Add the secondary VTTs.
199a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville  LayoutSecondaryVTTs(Base);
200a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
201a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville  // Add the secondary virtual pointers.
202a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville  LayoutSecondaryVirtualPointers(Base, VTableIndex);
203a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
204a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville  // If this is the primary VTT, we want to lay out virtual VTTs as well.
205a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville  if (IsPrimaryVTT) {
206a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    VisitedVirtualBasesSetTy VBases;
207a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    LayoutVirtualVTTs(Base.getBase(), VBases);
208a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville  }
209a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville}
210a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville