diff options
Diffstat (limited to 'lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 113 |
1 files changed, 81 insertions, 32 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 88d71ce..13fae29 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -73,22 +73,11 @@ class EmptySubobjectMap { /// member subobject that is empty. void ComputeEmptySubobjectSizes(); - bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, - uint64_t Offset) const; - void AddSubobjectAtOffset(const CXXRecordDecl *RD, uint64_t Offset); - bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, - uint64_t Offset); void UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, uint64_t Offset, bool PlacingEmptyBase); - bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *Class, - uint64_t Offset) const; - bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, - uint64_t Offset) const; - void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, const CXXRecordDecl *Class, uint64_t Offset); @@ -100,6 +89,19 @@ class EmptySubobjectMap { return Offset <= MaxEmptyClassOffset; } +protected: + bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, + uint64_t Offset) const; + + bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, + uint64_t Offset); + + bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + uint64_t Offset) const; + bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, + uint64_t Offset) const; + public: /// This holds the size of the largest empty subobject (either a base /// or a member). Will be zero if the record being built doesn't contain @@ -513,6 +515,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD, } class RecordLayoutBuilder { +protected: // FIXME: Remove this and make the appropriate fields public. friend class clang::ASTContext; @@ -623,12 +626,14 @@ class RecordLayoutBuilder { void SelectPrimaryVBase(const CXXRecordDecl *RD); + virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const; + /// IdentifyPrimaryBases - Identify all virtual base classes, direct or /// indirect, that are primary base classes for some other direct or indirect /// base class. void IdentifyPrimaryBases(const CXXRecordDecl *RD); - bool IsNearlyEmpty(const CXXRecordDecl *RD) const; + virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const; /// LayoutNonVirtualBases - Determines the primary base class (if any) and /// lays it out. Will then proceed to lay out all non-virtual base clasess. @@ -638,7 +643,7 @@ class RecordLayoutBuilder { void LayoutNonVirtualBase(const BaseSubobjectInfo *Base); void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, - uint64_t Offset); + uint64_t Offset); /// LayoutVirtualBases - Lays out all the virtual bases. void LayoutVirtualBases(const CXXRecordDecl *RD, @@ -664,6 +669,8 @@ class RecordLayoutBuilder { void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT public: static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); + + virtual ~RecordLayoutBuilder() { } }; } // end anonymous namespace @@ -734,6 +741,11 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { } } +uint64_t +RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { + return Context.Target.getPointerWidth(0); +} + /// DeterminePrimaryBase - Determine the primary base of the given class. void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // If the class isn't dynamic, it won't have a primary base. @@ -794,7 +806,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); // Update the size. - Size += Context.Target.getPointerWidth(0); + Size += GetVirtualPointersSize(RD); DataSize = Size; // Update the alignment. @@ -1123,8 +1135,8 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>()) MaxFieldAlignment = MFAA->getAlignment(); - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - UpdateAlignment(AA->getMaxAlignment()); + if (unsigned MaxAlign = D->getMaxAlignment()) + UpdateAlignment(MaxAlign); } } @@ -1287,8 +1299,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) FieldAlign = 1; - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); + FieldAlign = std::max(FieldAlign, D->getMaxAlignment()); // The maximum field alignment overrides the aligned attribute. if (MaxFieldAlignment) @@ -1357,8 +1368,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { if (FieldPacked) FieldAlign = 8; - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); + FieldAlign = std::max(FieldAlign, D->getMaxAlignment()); // The maximum field alignment overrides the aligned attribute. if (MaxFieldAlignment) @@ -1453,6 +1463,37 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { return 0; } +// This class implements layout specific to the Microsoft ABI. +class MSRecordLayoutBuilder: public RecordLayoutBuilder { +public: + MSRecordLayoutBuilder(ASTContext& Ctx, EmptySubobjectMap *EmptySubobjects): + RecordLayoutBuilder(Ctx, EmptySubobjects) {} + + virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const; + virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const; +}; + +bool MSRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { + // FIXME: Audit the corners + if (!RD->isDynamicClass()) + return false; + const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); + // In the Microsoft ABI, classes can have one or two vtable pointers. + if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) || + BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) * 2) + return true; + return false; +} + +uint64_t +MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { + // We should reserve space for two pointers if the class has both + // virtual functions and virtual bases. + if (RD->isPolymorphic() && RD->getNumVBases() > 0) + return 2 * Context.Target.getPointerWidth(0); + return Context.Target.getPointerWidth(0); +} + /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field /// position information. @@ -1471,8 +1512,16 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { EmptySubobjectMap EmptySubobjects(*this, RD); - RecordLayoutBuilder Builder(*this, &EmptySubobjects); - Builder.Layout(RD); + // When compiling for Microsoft, use the special MS builder. + llvm::OwningPtr<RecordLayoutBuilder> Builder; + switch (Target.getCXXABI()) { + default: + Builder.reset(new RecordLayoutBuilder(*this, &EmptySubobjects)); + break; + case CXXABI_Microsoft: + Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects)); + } + Builder->Layout(RD); // FIXME: This is not always correct. See the part about bitfields at // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. @@ -1481,20 +1530,20 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { // FIXME: This should be done in FinalizeLayout. uint64_t DataSize = - IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize; + IsPODForThePurposeOfLayout ? Builder->Size : Builder->DataSize; uint64_t NonVirtualSize = - IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; + IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize; NewEntry = - new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment, - DataSize, Builder.FieldOffsets.data(), - Builder.FieldOffsets.size(), + new (*this) ASTRecordLayout(*this, Builder->Size, Builder->Alignment, + DataSize, Builder->FieldOffsets.data(), + Builder->FieldOffsets.size(), NonVirtualSize, - Builder.NonVirtualAlignment, + Builder->NonVirtualAlignment, EmptySubobjects.SizeOfLargestEmptySubobject, - Builder.PrimaryBase, - Builder.PrimaryBaseIsVirtual, - Builder.Bases, Builder.VBases); + Builder->PrimaryBase, + Builder->PrimaryBaseIsVirtual, + Builder->Bases, Builder->VBases); } else { RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); Builder.Layout(D); @@ -1630,7 +1679,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, if (const RecordType *RT = Field->getType()->getAs<RecordType>()) { if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) { DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel, - Field->getNameAsCString(), + Field->getName().data(), /*IncludeVirtualBases=*/true); continue; } |