summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/RecordLayoutBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp715
1 files changed, 377 insertions, 338 deletions
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 832bfef90c9..5191cb2e73d 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -1189,7 +1189,7 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
}
}
- CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign();
+ CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlignment();
CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
// If we have an empty base class, try to place it at offset 0.
@@ -2026,10 +2026,16 @@ static bool isMsLayout(const RecordDecl* D) {
// added for bases is 1 byte. The padding added for vbases depends on the
// alignment of the object but is at least 4 bytes (in both 32 and 64 bit
// modes).
+// * There is no concept of non-virtual alignment or any distinction between
+// data size and non-virtual size.
namespace {
struct MicrosoftRecordLayoutBuilder {
+ struct ElementInfo {
+ CharUnits Size;
+ CharUnits Alignment;
+ };
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
MicrosoftRecordLayoutBuilder(const ASTContext &Context) : Context(Context) {}
private:
@@ -2037,7 +2043,6 @@ private:
LLVM_DELETED_FUNCTION;
void operator=(const MicrosoftRecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
public:
-
void layout(const RecordDecl *RD);
void cxxLayout(const CXXRecordDecl *RD);
/// \brief Initializes size and alignment and honors some flags.
@@ -2046,10 +2051,13 @@ public:
/// existence of vfptrs and vbptrs. Alignment is needed before the vfptr is
/// laid out.
void initializeCXXLayout(const CXXRecordDecl *RD);
- void layoutVFPtr(const CXXRecordDecl *RD);
void layoutNonVirtualBases(const CXXRecordDecl *RD);
- void layoutNonVirtualBase(const CXXRecordDecl *RD);
- void layoutVBPtr(const CXXRecordDecl *RD);
+ void layoutNonVirtualBase(const CXXRecordDecl *BaseDecl,
+ const ASTRecordLayout &BaseLayout,
+ const ASTRecordLayout *&PreviousBaseLayout);
+ void injectVFPtr(const CXXRecordDecl *RD);
+ void injectVBPtr(const CXXRecordDecl *RD);
+ void injectVPtrs(const CXXRecordDecl *RD);
/// \brief Lays out the fields of the record. Also rounds size up to
/// alignment.
void layoutFields(const RecordDecl *RD);
@@ -2058,22 +2066,19 @@ public:
/// \brief Lays out a single zero-width bit-field in the record and handles
/// special cases associated with zero-width bit-fields.
void layoutZeroWidthBitField(const FieldDecl *FD);
- void fixSizeAndAlignment(const RecordDecl *FD);
void layoutVirtualBases(const CXXRecordDecl *RD);
- void layoutVirtualBase(const CXXRecordDecl *RD, bool HasVtordisp);
void finalizeLayout(const RecordDecl *RD);
-
- /// \brief Updates the alignment of the type. This function doesn't take any
- /// properties (such as packedness) into account. getAdjustedFieldInfo()
- /// adjustes for packedness.
- void updateAlignment(CharUnits NewAlignment) {
- Alignment = std::max(Alignment, NewAlignment);
- }
- CharUnits getBaseAlignment(const ASTRecordLayout& Layout);
- /// \brief Gets the size and alignment taking attributes into account.
- std::pair<CharUnits, CharUnits> getAdjustedFieldInfo(const FieldDecl *FD);
- /// \brief Places a field at offset 0.
- void placeFieldAtZero() { FieldOffsets.push_back(0); }
+ /// \brief Gets the size and alignment of a base taking pragma pack and
+ /// __declspec(align) into account.
+ ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout);
+ /// \brief Gets the size and alignment of a field taking pragma pack and
+ /// __declspec(align) into account. It also updates RequiredAlignment as a
+ /// side effect because it is most convenient to do so here.
+ ElementInfo getAdjustedElementInfo(const FieldDecl *FD);
+ /// \brief Updates the alignment of the record.
+ void updateAlignment(CharUnits MemberAlignment) {
+ Alignment = std::max(Alignment, MemberAlignment);
+ }
/// \brief Places a field at an offset in CharUnits.
void placeFieldAtOffset(CharUnits FieldOffset) {
FieldOffsets.push_back(Context.toBits(FieldOffset));
@@ -2085,66 +2090,48 @@ public:
/// \brief Compute the set of virtual bases for which vtordisps are required.
llvm::SmallPtrSet<const CXXRecordDecl *, 2>
computeVtorDispSet(const CXXRecordDecl *RD);
-
const ASTContext &Context;
/// \brief The size of the record being laid out.
CharUnits Size;
+ /// \brief The data alignment of the record layout.
+ CharUnits DataSize;
/// \brief The current alignment of the record layout.
CharUnits Alignment;
- /// \brief The collection of field offsets.
- SmallVector<uint64_t, 16> FieldOffsets;
/// \brief The maximum allowed field alignment. This is set by #pragma pack.
CharUnits MaxFieldAlignment;
/// \brief The alignment that this record must obey. This is imposed by
/// __declspec(align()) on the record itself or one of its fields or bases.
CharUnits RequiredAlignment;
- bool IsUnion : 1;
- /// \brief True if the last field laid out was a bitfield and was not 0
- /// width.
- bool LastFieldIsNonZeroWidthBitfield : 1;
/// \brief The size of the allocation of the currently active bitfield.
/// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield
/// is true.
CharUnits CurrentBitfieldSize;
- /// \brief The number of remaining bits in our last bitfield allocation.
- /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is
- /// true.
- unsigned RemainingBitsInField;
-
- /// \brief The data alignment of the record layout.
- CharUnits DataSize;
- /// \brief The alignment of the non-virtual portion of the record layout
- /// without the impact of the virtual pointers.
- /// Only used for C++ layouts.
- CharUnits BasesAndFieldsAlignment;
- /// \brief The alignment of the non-virtual portion of the record layout
- /// Only used for C++ layouts.
- CharUnits NonVirtualAlignment;
+ /// \brief Offset to the virtual base table pointer (if one exists).
+ CharUnits VBPtrOffset;
+ /// \brief The size and alignment info of a pointer.
+ ElementInfo PointerInfo;
/// \brief The primary base class (if one exists).
const CXXRecordDecl *PrimaryBase;
/// \brief The class we share our vb-pointer with.
const CXXRecordDecl *SharedVBPtrBase;
- /// \brief True if the class has a vftable pointer that can be extended
- /// by this class or classes derived from it. Such a vfptr will always occur
- /// at offset 0.
- bool HasExtendableVFPtr : 1;
- /// \brief True if the class has a (not necessarily its own) vbtable pointer.
- bool HasVBPtr : 1;
- /// \brief Offset to the virtual base table pointer (if one exists).
- CharUnits VBPtrOffset;
+ /// \brief The collection of field offsets.
+ SmallVector<uint64_t, 16> FieldOffsets;
/// \brief Base classes and their offsets in the record.
BaseOffsetsMapTy Bases;
/// \brief virtual base classes and their offsets in the record.
ASTRecordLayout::VBaseOffsetsMapTy VBases;
- /// \brief The size of a pointer.
- CharUnits PointerSize;
- /// \brief The alignment of a pointer.
- CharUnits PointerAlignment;
- /// \brief Holds an empty base we haven't yet laid out.
- const CXXRecordDecl *LazyEmptyBase;
- /// \brief A pointer to the Layout for the most recent non-virtual base that
- /// has been laid out.
- const ASTRecordLayout *PreviousBaseLayout;
+ /// \brief The number of remaining bits in our last bitfield allocation.
+ /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is
+ /// true.
+ unsigned RemainingBitsInField;
+ bool IsUnion : 1;
+ /// \brief True if the last field laid out was a bitfield and was not 0
+ /// width.
+ bool LastFieldIsNonZeroWidthBitfield : 1;
+ /// \brief True if the class has its own vftable pointer.
+ bool HasOwnVFPtr : 1;
+ /// \brief True if the class has a vbtable pointer.
+ bool HasVBPtr : 1;
/// \brief Lets us know if we're in 64-bit mode
bool Is64BitMode : 1;
/// \brief True if this class contains a zero sized member or base or a base
@@ -2156,61 +2143,92 @@ public:
};
} // namespace
-CharUnits
-MicrosoftRecordLayoutBuilder::getBaseAlignment(const ASTRecordLayout& Layout) {
- CharUnits BaseAlignment = Layout.getAlignment();
+MicrosoftRecordLayoutBuilder::ElementInfo
+MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
+ const ASTRecordLayout &Layout) {
+ ElementInfo Info;
+ Info.Alignment = Layout.getAlignment();
+ // Respect pragma pack.
if (!MaxFieldAlignment.isZero())
- BaseAlignment = std::min(BaseAlignment,
- std::max(MaxFieldAlignment,
- Layout.getRequiredAlignment()));
- return BaseAlignment;
+ Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
+ // Track zero-sized subobjects here where it's already available.
+ if (Layout.hasZeroSizedSubObject())
+ HasZeroSizedSubObject = true;
+ // Respect required alignment, this is necessary because we may have adjusted
+ // the alignment in the case of pragam pack.
+ Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment());
+ Info.Size = Layout.getNonVirtualSize();
+ return Info;
}
-std::pair<CharUnits, CharUnits>
-MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) {
- std::pair<CharUnits, CharUnits> FieldInfo =
- Context.getTypeInfoInChars(FD->getType());
-
- // Respect packed attribute.
- if (FD->hasAttr<PackedAttr>())
- FieldInfo.second = CharUnits::One();
- // Respect pack pragma.
- else if (!MaxFieldAlignment.isZero())
- FieldInfo.second = std::min(FieldInfo.second, MaxFieldAlignment);
- // Respect alignment attributes.
- if (unsigned fieldAlign = FD->getMaxAlignment()) {
- CharUnits FieldAlign = Context.toCharUnitsFromBits(fieldAlign);
- RequiredAlignment = std::max(RequiredAlignment, FieldAlign);
- FieldInfo.second = std::max(FieldInfo.second, FieldAlign);
- }
+MicrosoftRecordLayoutBuilder::ElementInfo
+MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
+ const FieldDecl *FD) {
+ ElementInfo Info;
// Respect attributes applied to subobjects of the field.
if (const RecordType *RT =
FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RT->getDecl());
+ // Get the element info for a layout, respecting pack.
+ Info = getAdjustedElementInfo(Layout);
+ // Nomally getAdjustedElementInfo returns the non-virtual size, which is
+ // correct for bases but not for fields.
+ Info.Size = Layout.getSize();
+ // Capture required alignment as a side-effect.
RequiredAlignment = std::max(RequiredAlignment,
Layout.getRequiredAlignment());
- FieldInfo.second = std::max(FieldInfo.second,
- Layout.getRequiredAlignment());
- // Track zero-sized subobjects here where it's already available.
- if (Layout.hasZeroSizedSubObject())
- HasZeroSizedSubObject = true;
}
- return FieldInfo;
+ else {
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(FD->getType());
+ Info.Size = FieldInfo.first;
+ Info.Alignment = FieldInfo.second;
+ // Respect pragma pack.
+ if (!MaxFieldAlignment.isZero())
+ Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
+ }
+ // Respect packed field attribute.
+ if (FD->hasAttr<PackedAttr>())
+ Info.Alignment = CharUnits::One();
+ // Respect align attributes.
+ CharUnits FieldRequiredAlignment =
+ Context.toCharUnitsFromBits(FD->getMaxAlignment());
+ // Take required alignment into account.
+ Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
+ // Capture required alignment as a side-effect.
+ RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment);
+ return Info;
+}
+
+void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
+ initializeLayout(RD);
+ layoutFields(RD);
+ DataSize = Size = Size.RoundUpToAlignment(Alignment);
+ finalizeLayout(RD);
+}
+
+void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
+ initializeLayout(RD);
+ initializeCXXLayout(RD);
+ layoutNonVirtualBases(RD);
+ layoutFields(RD);
+ injectVPtrs(RD);
+ DataSize = Size = Size.RoundUpToAlignment(Alignment);
+ layoutVirtualBases(RD);
+ finalizeLayout(RD);
}
void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
IsUnion = RD->isUnion();
Is64BitMode = Context.getTargetInfo().getPointerWidth(0) == 64;
-
Size = CharUnits::Zero();
Alignment = CharUnits::One();
-
// In 64-bit mode we always perform an alignment step after laying out vbases.
// In 32-bit mode we do not. The check to see if we need to perform alignment
// checks the RequiredAlignment field and performs alignment if it isn't 0.
RequiredAlignment = Is64BitMode ? CharUnits::One() : CharUnits::Zero();
- HasZeroSizedSubObject = false;
-
+ RequiredAlignment = std::max(RequiredAlignment,
+ Context.toCharUnitsFromBits(RD->getMaxAlignment()));
// Compute the maximum field alignment.
MaxFieldAlignment = CharUnits::Zero();
// Honor the default struct packing maximum alignment flag.
@@ -2224,118 +2242,70 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
MaxFieldAlignment = CharUnits::One();
}
-void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
- initializeLayout(RD);
- layoutFields(RD);
- fixSizeAndAlignment(RD);
- finalizeLayout(RD);
-}
-
-void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
- initializeLayout(RD);
- initializeCXXLayout(RD);
- layoutVFPtr(RD);
- layoutNonVirtualBases(RD);
- layoutVBPtr(RD);
- layoutFields(RD);
- fixSizeAndAlignment(RD);
- layoutVirtualBases(RD);
- finalizeLayout(RD);
-}
-
void
MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
- // Calculate pointer size and alignment.
- PointerSize =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- PointerAlignment = PointerSize;
- if (!MaxFieldAlignment.isZero())
- PointerAlignment = std::min(PointerAlignment, MaxFieldAlignment);
-
- // Initialize information about the bases.
+ HasZeroSizedSubObject = false;
+ LeadsWithZeroSizedBase = false;
+ HasOwnVFPtr = false;
HasVBPtr = false;
- HasExtendableVFPtr = false;
- SharedVBPtrBase = 0;
PrimaryBase = 0;
- LeadsWithZeroSizedBase = false;
+ SharedVBPtrBase = 0;
+ // Calculate pointer size and alignment. These are used for vfptr and vbprt
+ // injection.
+ PointerInfo.Size =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ PointerInfo.Alignment = PointerInfo.Size;
+ // Respect pragma pack.
+ if (!MaxFieldAlignment.isZero())
+ PointerInfo.Alignment = std::min(PointerInfo.Alignment, MaxFieldAlignment);
+}
- // If the record has a dynamic base class, attempt to choose a primary base
- // class. It is the first (in direct base class order) non-virtual dynamic
- // base class, if one exists.
+void
+MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
+ // The MS-ABI lays out all bases that contain leading vfptrs before it lays
+ // out any bases that do not contain vfptrs. We implement this as two passes
+ // over the bases. This approach guarantees that the primary base is laid out
+ // first. We use these passes to calculate some additional aggregated
+ // information about the bases, such as reqruied alignment and the presence of
+ // zero sized members.
+ const ASTRecordLayout* PreviousBaseLayout = 0;
+ // Iterate through the bases and lay out the non-virtual ones.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end();
i != e; ++i) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
- // Handle required alignment.
+ const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl();
+ const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
+ // Track RequiredAlignment for all bases in this pass.
RequiredAlignment = std::max(RequiredAlignment,
- Layout.getRequiredAlignment());
- // Check for zero sized subobjects.
- if (Layout.hasZeroSizedSubObject())
- HasZeroSizedSubObject = true;
- // Handle virtual bases.
+ BaseLayout.getRequiredAlignment());
+ // Mark and skip virtual bases.
if (i->isVirtual()) {
HasVBPtr = true;
continue;
}
- // We located a primary base class!
- if (!PrimaryBase && Layout.hasExtendableVFPtr()) {
- PrimaryBase = BaseDecl;
- HasExtendableVFPtr = true;
- }
- // We located a base to share a VBPtr with!
- if (!SharedVBPtrBase && Layout.hasVBPtr()) {
+ // Check fo a base to share a VBPtr with.
+ if (!SharedVBPtrBase && BaseLayout.hasVBPtr()) {
SharedVBPtrBase = BaseDecl;
HasVBPtr = true;
}
- updateAlignment(getBaseAlignment(Layout));
+ // Only lay out bases with extendable VFPtrs on the first pass.
+ if (!BaseLayout.hasExtendableVFPtr())
+ continue;
+ // If we don't have a primary base, this one qualifies.
+ if (!PrimaryBase)
+ PrimaryBase = BaseDecl;
+ // Lay out the base.
+ layoutNonVirtualBase(BaseDecl, BaseLayout, PreviousBaseLayout);
}
-
- // Use LayoutFields to compute the alignment of the fields. The layout
- // is discarded. This is the simplest way to get all of the bit-field
- // behavior correct and is not actually very expensive.
- layoutFields(RD);
- Size = CharUnits::Zero();
- BasesAndFieldsAlignment = Alignment;
- FieldOffsets.clear();
-}
-
-void MicrosoftRecordLayoutBuilder::layoutVFPtr(const CXXRecordDecl *RD) {
- // If we have a primary base then our VFPtr was already laid out
- if (PrimaryBase)
- return;
-
- // Look at all of our methods to determine if we need a VFPtr. We need a
- // vfptr if we define a new virtual function.
- if (!HasExtendableVFPtr && RD->isDynamicClass())
+ // Figure out if we need a fresh VFPtr for this class.
+ if (!PrimaryBase && RD->isDynamicClass())
for (CXXRecordDecl::method_iterator i = RD->method_begin(),
e = RD->method_end();
- !HasExtendableVFPtr && i != e; ++i)
- HasExtendableVFPtr = i->isVirtual() && i->size_overridden_methods() == 0;
- if (!HasExtendableVFPtr)
- return;
-
- updateAlignment(PointerAlignment);
- Size = Size.RoundUpToAlignment(PointerAlignment) + PointerSize;
- // MSVC 32 (but not 64) potentially over-aligns the vf-table pointer by giving
- // it the max alignment of all the non-virtual data in the class. The
- // resulting layout is essentially { vftbl, { nvdata } }. This is completely
- // unnecessary, but we're not here to pass judgment.
- if (!Is64BitMode && Alignment > PointerSize)
- Size += Alignment - PointerSize;
-}
-
-void
-MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
- LazyEmptyBase = 0;
- PreviousBaseLayout = 0;
-
- // Lay out the primary base first.
- if (PrimaryBase)
- layoutNonVirtualBase(PrimaryBase);
-
- const CXXRecordDecl *LeadingBase = PrimaryBase;
+ !HasOwnVFPtr && i != e; ++i)
+ HasOwnVFPtr = i->isVirtual() && i->size_overridden_methods() == 0;
+ // If we don't have a primary base then we have a leading object that could
+ // itself lead with a zero-sized object, something we track.
+ bool CheckLeadingLayout = !PrimaryBase;
// Iterate through the bases and lay out the non-virtual ones.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end();
@@ -2343,71 +2313,41 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
if (i->isVirtual())
continue;
const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl();
- if (BaseDecl == PrimaryBase)
+ const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
+ // Only lay out bases without extendable VFPtrs on the second pass.
+ if (BaseLayout.hasExtendableVFPtr())
continue;
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
- if (!LeadingBase) {
- LeadsWithZeroSizedBase = Layout.leadsWithZeroSizedBase();
- LeadingBase = BaseDecl;
- }
-
- if (LazyEmptyBase) {
- layoutNonVirtualBase(LazyEmptyBase);
- LazyEmptyBase = 0;
+ // If this is the first layout, check to see if it leads with a zero sized
+ // object. If it does, so do we.
+ if (CheckLeadingLayout) {
+ CheckLeadingLayout = false;
+ LeadsWithZeroSizedBase = BaseLayout.leadsWithZeroSizedBase();
}
- // Insert padding between two bases if the left first one is zero sized or
- // contains a zero sized subobject and the right is zero sized or one leads
- // with a zero sized base.
- if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
- Layout.leadsWithZeroSizedBase())
- Size++;
- if (Layout.getNonVirtualSize().isZero())
- LazyEmptyBase = BaseDecl;
- else
- layoutNonVirtualBase(BaseDecl);
+ // Lay out the base.
+ layoutNonVirtualBase(BaseDecl, BaseLayout, PreviousBaseLayout);
}
-}
-
-void
-MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- // Insert the base here.
- CharUnits BaseOffset = Size.RoundUpToAlignment(getBaseAlignment(Layout));
- Bases.insert(std::make_pair(RD, BaseOffset));
- Size = BaseOffset + Layout.getDataSize();
- // Alignment was upadated in InitializeCXXLayout.
- PreviousBaseLayout = &Layout;
-}
-
-void MicrosoftRecordLayoutBuilder::layoutVBPtr(const CXXRecordDecl *RD) {
+ // Set our VBPtroffset if we know it at this point.
if (!HasVBPtr)
VBPtrOffset = CharUnits::fromQuantity(-1);
- else if (SharedVBPtrBase)
- VBPtrOffset = Bases[SharedVBPtrBase] +
- Context.getASTRecordLayout(SharedVBPtrBase).getVBPtrOffset();
- else {
- VBPtrOffset = Size.RoundUpToAlignment(PointerAlignment);
- CharUnits OldSize = Size;
- Size = VBPtrOffset + PointerSize;
- if (BasesAndFieldsAlignment <= PointerAlignment)
- // Handle strange padding rules for the lazily placed base. I have no
- // explanation for why the last virtual base is padded in such an odd way.
- // Two things to note about this padding are that the rules are different
- // if the alignment of the bases+fields is <= to the alignemnt of a
- // pointer and that the rule in 64-bit mode behaves differently depending
- // on if the second to last base was also zero sized.
- Size += OldSize % BasesAndFieldsAlignment.getQuantity();
- else {
- if (!Is64BitMode)
- Size = OldSize + BasesAndFieldsAlignment;
- else if (PreviousBaseLayout &&
- PreviousBaseLayout->getNonVirtualSize().isZero())
- Size += CharUnits::One();
- }
- updateAlignment(PointerAlignment);
- }
- if (LazyEmptyBase)
- layoutNonVirtualBase(LazyEmptyBase);
+}
+
+void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
+ const CXXRecordDecl *BaseDecl,
+ const ASTRecordLayout &BaseLayout,
+ const ASTRecordLayout *&PreviousBaseLayout) {
+ // Insert padding between two bases if the left first one is zero sized or
+ // contains a zero sized subobject and the right is zero sized or one leads
+ // with a zero sized base.
+ if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
+ BaseLayout.leadsWithZeroSizedBase())
+ Size++;
+ ElementInfo Info = getAdjustedElementInfo(BaseLayout);
+ CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ Bases.insert(std::make_pair(BaseDecl, BaseOffset));
+ Size = BaseOffset + BaseLayout.getDataSize();
+ updateAlignment(Info.Alignment);
+ PreviousBaseLayout = &BaseLayout;
+ VBPtrOffset = Size;
}
void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) {
@@ -2416,7 +2356,6 @@ void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) {
FieldEnd = RD->field_end();
Field != FieldEnd; ++Field)
layoutField(*Field);
- Size = Size.RoundUpToAlignment(Alignment);
}
void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
@@ -2425,21 +2364,16 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
return;
}
LastFieldIsNonZeroWidthBitfield = false;
-
- std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
- CharUnits FieldSize = FieldInfo.first;
- CharUnits FieldAlign = FieldInfo.second;
-
- updateAlignment(FieldAlign);
+ ElementInfo Info = getAdjustedElementInfo(FD);
if (IsUnion) {
- placeFieldAtZero();
- Size = std::max(Size, FieldSize);
+ placeFieldAtOffset(CharUnits::Zero());
+ Size = std::max(Size, Info.Size);
} else {
- // Round up the current record size to the field's alignment boundary.
- CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
placeFieldAtOffset(FieldOffset);
- Size = FieldOffset + FieldSize;
+ Size = FieldOffset + Info.Size;
}
+ updateAlignment(Info.Alignment);
}
void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
@@ -2448,39 +2382,33 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
layoutZeroWidthBitField(FD);
return;
}
-
- std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
- CharUnits FieldSize = FieldInfo.first;
- CharUnits FieldAlign = FieldInfo.second;
-
+ ElementInfo Info = getAdjustedElementInfo(FD);
// Clamp the bitfield to a containable size for the sake of being able
// to lay them out. Sema will throw an error.
- if (Width > Context.toBits(FieldSize))
- Width = Context.toBits(FieldSize);
-
+ if (Width > Context.toBits(Info.Size))
+ Width = Context.toBits(Info.Size);
// Check to see if this bitfield fits into an existing allocation. Note:
// MSVC refuses to pack bitfields of formal types with different sizes
// into the same allocation.
if (!IsUnion && LastFieldIsNonZeroWidthBitfield &&
- CurrentBitfieldSize == FieldSize && Width <= RemainingBitsInField) {
+ CurrentBitfieldSize == Info.Size && Width <= RemainingBitsInField) {
placeFieldAtBitOffset(Context.toBits(Size) - RemainingBitsInField);
RemainingBitsInField -= Width;
return;
}
-
LastFieldIsNonZeroWidthBitfield = true;
- CurrentBitfieldSize = FieldSize;
+ CurrentBitfieldSize = Info.Size;
if (IsUnion) {
- placeFieldAtZero();
- Size = std::max(Size, FieldSize);
+ placeFieldAtOffset(CharUnits::Zero());
+ Size = std::max(Size, Info.Size);
// TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
} else {
// Allocate a new block of memory and place the bitfield in it.
- CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
placeFieldAtOffset(FieldOffset);
- Size = FieldOffset + FieldSize;
- updateAlignment(FieldAlign);
- RemainingBitsInField = Context.toBits(FieldSize) - Width;
+ Size = FieldOffset + Info.Size;
+ updateAlignment(Info.Alignment);
+ RemainingBitsInField = Context.toBits(Info.Size) - Width;
}
}
@@ -2488,96 +2416,210 @@ void
MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
// Zero-width bitfields are ignored unless they follow a non-zero-width
// bitfield.
- std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
- CharUnits FieldSize = FieldInfo.first;
- CharUnits FieldAlign = FieldInfo.second;
-
if (!LastFieldIsNonZeroWidthBitfield) {
placeFieldAtOffset(IsUnion ? CharUnits::Zero() : Size);
// TODO: Add a Sema warning that MS ignores alignment for zero
// sized bitfields that occur after zero-size bitfields or non-bitfields.
return;
}
-
LastFieldIsNonZeroWidthBitfield = false;
+ ElementInfo Info = getAdjustedElementInfo(FD);
if (IsUnion) {
- placeFieldAtZero();
- Size = std::max(Size, FieldSize);
+ placeFieldAtOffset(CharUnits::Zero());
+ Size = std::max(Size, Info.Size);
} else {
// Round up the current record size to the field's alignment boundary.
- CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
placeFieldAtOffset(FieldOffset);
Size = FieldOffset;
- updateAlignment(FieldAlign);
+ updateAlignment(Info.Alignment);
}
}
-void MicrosoftRecordLayoutBuilder::fixSizeAndAlignment(const RecordDecl *RD) {
- DataSize = Size;
- NonVirtualAlignment = Alignment;
- RequiredAlignment = std::max(RequiredAlignment,
- Context.toCharUnitsFromBits(RD->getMaxAlignment()));
- updateAlignment(RequiredAlignment);
+void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) {
+ if (!HasVBPtr)
+ return;
+ if (SharedVBPtrBase) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(SharedVBPtrBase);
+ VBPtrOffset = Bases[SharedVBPtrBase] + Layout.getVBPtrOffset();
+ return;
+ }
+ // Inject the VBPointer at the injection site.
+ CharUnits InjectionSite = VBPtrOffset;
+ // But before we do, make sure it's properly aligned.
+ VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment);
+ // Determine where the first field should be laid out after the vbptr.
+ CharUnits FieldStart = VBPtrOffset + PointerInfo.Size;
+ // Make sure that the amount we push the fields back by is a multiple of the
+ // alignment.
+ CharUnits Offset = (FieldStart - InjectionSite).RoundUpToAlignment(Alignment);
+ // Increase the size of the object and push back all fields by the offset
+ // amount.
+ Size += Offset;
+ for (SmallVector<uint64_t, 16>::iterator i = FieldOffsets.begin(),
+ e = FieldOffsets.end();
+ i != e; ++i)
+ *i += Context.toBits(Offset);
+ for (BaseOffsetsMapTy::iterator i = Bases.begin(), e = Bases.end();
+ i != e; ++i)
+ if (i->second >= InjectionSite)
+ i->second += Offset;
+ // Update the object alignment.
+ updateAlignment(PointerInfo.Alignment);
}
-void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
- if (!HasVBPtr)
+void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
+ if (!HasOwnVFPtr)
return;
+ // Make sure that the amount we push the struct back by is a multiple of the
+ // alignment.
+ CharUnits Offset = PointerInfo.Size.RoundUpToAlignment(Alignment);
+ // Increase the size of the object and push back all fields, the vbptr and all
+ // bases by the offset amount.
+ Size += Offset;
+ for (SmallVector<uint64_t, 16>::iterator i = FieldOffsets.begin(),
+ e = FieldOffsets.end();
+ i != e; ++i)
+ *i += Context.toBits(Offset);
+ if (HasVBPtr)
+ VBPtrOffset += Offset;
+ for (BaseOffsetsMapTy::iterator i = Bases.begin(), e = Bases.end();
+ i != e; ++i)
+ i->second += Offset;
+ updateAlignment(PointerInfo.Alignment);
+}
- PreviousBaseLayout = 0;
+void MicrosoftRecordLayoutBuilder::injectVPtrs(const CXXRecordDecl *RD) {
+ if (!(HasOwnVFPtr || HasVBPtr && !SharedVBPtrBase))
+ return;
+ if (!Is64BitMode || RequiredAlignment <= CharUnits::fromQuantity(8)) {
+ // Note that the VBPtr is injected first. It depends on the alignment of
+ // the object *before* the alignment is updated by inserting a pointer into
+ // the record.
+ injectVBPtr(RD);
+ injectVFPtr(RD);
+ return;
+ }
+ // In 64-bit mode, structs with RequiredAlignment greater than 8 get special
+ // layout rules. Likely this is to avoid excessive padding intruced around
+ // the vfptrs and vbptrs. The special rules involve re-laying out the struct
+ // and inserting the vfptr and vbptr as if they were fields/bases.
+ FieldOffsets.clear();
+ Bases.clear();
+ Size = CharUnits::Zero();
+ updateAlignment(PointerInfo.Alignment);
+ if (HasOwnVFPtr)
+ Size = PointerInfo.Size;
+ layoutNonVirtualBases(RD);
+ if (HasVBPtr && !SharedVBPtrBase) {
+ const CXXRecordDecl *PenultBaseDecl = 0;
+ const CXXRecordDecl *LastBaseDecl = 0;
+ // Iterate through the bases and find the last two non-virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end();
+ i != e; ++i) {
+ if (i->isVirtual())
+ continue;
+ const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl();
+ if (!LastBaseDecl || Bases[BaseDecl] > Bases[LastBaseDecl]) {
+ PenultBaseDecl = LastBaseDecl;
+ LastBaseDecl = BaseDecl;
+ }
+ }
+ const ASTRecordLayout *PenultBaseLayout = PenultBaseDecl ?
+ &Context.getASTRecordLayout(PenultBaseDecl) : 0;
+ const ASTRecordLayout *LastBaseLayout = LastBaseDecl ?
+ &Context.getASTRecordLayout(LastBaseDecl) : 0;
+ // Calculate the vbptr offset. The rule is different than in the general
+ // case layout. Particularly, if the last two non-virtual bases are both
+ // zero sized, the site of the vbptr is *before* the padding that occurs
+ // between the two zero sized bases and the vbptr potentially aliases with
+ // the first of these two bases. We have no understanding of why this is
+ // different from the general case layout but it may have to do with lazy
+ // placement of zero sized bases.
+ VBPtrOffset = Size;
+ if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) {
+ VBPtrOffset = Bases[LastBaseDecl];
+ if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero())
+ VBPtrOffset = Bases[PenultBaseDecl];
+ }
+ // Once we've located a spot for the vbptr, place it.
+ VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment);
+ Size = VBPtrOffset + PointerInfo.Size;
+ if (LastBaseLayout && LastBaseLayout->getNonVirtualSize().isZero()) {
+ // Add the padding between zero sized bases after the vbptr.
+ if (PenultBaseLayout && PenultBaseLayout->getNonVirtualSize().isZero())
+ Size += CharUnits::One();
+ Size = Size.RoundUpToAlignment(LastBaseLayout->getRequiredAlignment());
+ Bases[LastBaseDecl] = Size;
+ }
+ }
+ layoutFields(RD);
+}
- llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp =
+void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
+ if (!HasVBPtr)
+ return;
+ // Vtordisps are always 4 bytes (even in 64-bit mode)
+ CharUnits VtorDispSize = CharUnits::fromQuantity(4);
+ CharUnits VtorDispAlignment = VtorDispSize;
+ // vtordisps respect pragma pack.
+ if (!MaxFieldAlignment.isZero())
+ VtorDispAlignment = std::min(VtorDispAlignment, MaxFieldAlignment);
+ // The alignment of the vtordisp is at least the required alignment of the
+ // entire record. This requirement may be present to support vtordisp
+ // injection.
+ VtorDispAlignment = std::max(VtorDispAlignment, RequiredAlignment);
+ // Compute the vtordisp set.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordispSet =
computeVtorDispSet(RD);
-
// Iterate through the virtual bases and lay them out.
+ const ASTRecordLayout* PreviousBaseLayout = 0;
for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
e = RD->vbases_end();
i != e; ++i) {
const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl();
+ const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
+ bool HasVtordisp = HasVtordispSet.count(BaseDecl);
// If the last field we laid out was a non-zero length bitfield then add
// some extra padding for no obvious reason.
if (LastFieldIsNonZeroWidthBitfield)
Size += CurrentBitfieldSize;
- layoutVirtualBase(BaseDecl, HasVtordisp.count(BaseDecl));
+ // Insert padding between two bases if the left first one is zero sized or
+ // contains a zero sized subobject and the right is zero sized or one leads
+ // with a zero sized base. The padding between virtual bases is 4
+ // bytes (in both 32 and 64 bits modes) and always involves rounding up to
+ // the required alignment, we don't know why.
+ if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
+ BaseLayout.leadsWithZeroSizedBase())
+ Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize;
+ // Insert the vtordisp.
+ if (HasVtordisp)
+ Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize;
+ // Insert the virtual base.
+ ElementInfo Info = getAdjustedElementInfo(BaseLayout);
+ CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ VBases.insert(std::make_pair(BaseDecl,
+ ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
+ Size = BaseOffset + BaseLayout.getNonVirtualSize();
+ updateAlignment(Info.Alignment);
+ PreviousBaseLayout = &BaseLayout;
}
}
-void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD,
- bool HasVtordisp) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CharUnits Four = CharUnits::fromQuantity(4);
- // Insert padding between two bases if the left first one is zero sized or
- // contains a zero sized subobject and the right is zero sized or one leads
- // with a zero sized base. The minimal padding between virtual bases is 4
- // bytes (in both 32 and 64 bits modes), we don't know why.
- if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
- Layout.leadsWithZeroSizedBase())
- Size = Size.RoundUpToAlignment(std::max(Four, RequiredAlignment)) + Four;
-
- // vtordisps are always 4 bytes (even in 64-bit mode)
- if (HasVtordisp)
- Size = Size.RoundUpToAlignment(Alignment) + Four;
-
- // Insert the base here.
- Size = Size.RoundUpToAlignment(getBaseAlignment(Layout));
- // Update the alignment
- updateAlignment(getBaseAlignment(Layout));
- VBases.insert(
- std::make_pair(RD, ASTRecordLayout::VBaseInfo(Size, HasVtordisp)));
- Size += Layout.getNonVirtualSize();
- // Alignment was upadated in InitializeCXXLayout.
- PreviousBaseLayout = &Layout;
-}
-
void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
+ // Respect required alignment. Note that in 32-bit mode Required alignment
+ // may be 0 nad cause size not to be updated.
+ if (!RequiredAlignment.isZero()) {
+ Alignment = std::max(Alignment, RequiredAlignment);
+ Size = Size.RoundUpToAlignment(Alignment);
+ }
+ // Zero-sized structures have size equal to their alignment.
if (Size.isZero()) {
HasZeroSizedSubObject = true;
LeadsWithZeroSizedBase = true;
Size = Alignment;
}
-
- if (!RequiredAlignment.isZero())
- Size = Size.RoundUpToAlignment(Alignment);
}
static bool
@@ -2600,8 +2642,7 @@ RequiresVtordisp(const llvm::SmallPtrSet<const CXXRecordDecl *, 2> &HasVtordisp,
llvm::SmallPtrSet<const CXXRecordDecl *, 2>
MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
- llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp;
-
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordispSet;
// If any of our bases need a vtordisp for this type, so do we. Check our
// direct bases for vtordisp requirements.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
@@ -2615,9 +2656,8 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
be = Layout.getVBaseOffsetsMap().end();
bi != be; ++bi)
if (bi->second.hasVtorDisp())
- HasVtordisp.insert(bi->first);
+ HasVtordispSet.insert(bi->first);
}
-
// If we define a constructor or destructor and override a function that is
// defined in a virtual base's vtable, that virtual bases need a vtordisp.
// Here we collect a list of classes with vtables for which our virtual bases
@@ -2639,25 +2679,24 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
e = MD->end_overridden_methods();
if (i == e)
// If a virtual method has no-overrides it lives in its parent's vtable.
- HasVtordisp.insert(MD->getParent());
+ HasVtordispSet.insert(MD->getParent());
else
Work.insert(i, e);
// We've finished processing this element, remove it from the working set.
Work.erase(MD);
}
}
-
// Re-check all of our vbases for vtordisp requirements (in case their
// non-virtual bases have vtordisp requirements).
for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
e = RD->vbases_end();
i != e; ++i) {
const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl();
- if (!HasVtordisp.count(BaseDecl) && RequiresVtordisp(HasVtordisp, BaseDecl))
- HasVtordisp.insert(BaseDecl);
+ if (!HasVtordispSet.count(BaseDecl) &&
+ RequiresVtordisp(HasVtordispSet, BaseDecl))
+ HasVtordispSet.insert(BaseDecl);
}
-
- return HasVtordisp;
+ return HasVtordispSet;
}
/// \brief Get or compute information about the layout of the specified record
@@ -2670,11 +2709,11 @@ ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const {
Builder.cxxLayout(RD);
return new (*this) ASTRecordLayout(
*this, Builder.Size, Builder.Alignment, Builder.RequiredAlignment,
- Builder.HasExtendableVFPtr && !Builder.PrimaryBase,
- Builder.HasExtendableVFPtr,
+ Builder.HasOwnVFPtr,
+ Builder.HasOwnVFPtr || Builder.PrimaryBase,
Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(), Builder.DataSize,
- Builder.NonVirtualAlignment, CharUnits::Zero(), Builder.PrimaryBase,
+ Builder.Alignment, CharUnits::Zero(), Builder.PrimaryBase,
false, Builder.SharedVBPtrBase,
Builder.HasZeroSizedSubObject, Builder.LeadsWithZeroSizedBase,
Builder.Bases, Builder.VBases);
@@ -2998,7 +3037,7 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
PrintIndentNoOffset(OS, IndentLevel - 1);
OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
- OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << "]\n";
+ OS << ", nvalign=" << Layout.getNonVirtualAlignment().getQuantity() << "]\n";
OS << '\n';
}
OpenPOWER on IntegriCloud