summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/RecordLayoutBuilder.cpp
diff options
context:
space:
mode:
authorWarren Hunt <whunt@google.com>2014-01-09 00:30:56 +0000
committerWarren Hunt <whunt@google.com>2014-01-09 00:30:56 +0000
commitd640d7d96e93f138e1aa844d91c868485a6b113d (patch)
treedd1de46e0a7bfeddd1ba5f7c045a817e986d1b2d /clang/lib/AST/RecordLayoutBuilder.cpp
parentd2d23ed04a08eb04ef2d6d0a89284f1f510e9d96 (diff)
downloadbcm5719-llvm-d640d7d96e93f138e1aa844d91c868485a6b113d.tar.gz
bcm5719-llvm-d640d7d96e93f138e1aa844d91c868485a6b113d.zip
[ms-abi] Refactor Microsoft Record Layout
This patch refactors microsoft record layout to be more "natural". The most dominant change is that vbptrs and vfptrs are injected after the fact. This simplifies the implementation and the math for the offest for the first base/field after the vbptr. llvm-svn: 198818
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