From: Timur Iskhodzhanov Date: Wed, 5 Jun 2013 14:05:50 +0000 (+0000) Subject: Recommit r183298+r183300 'Get rid of VTableContext::ComputeMethodVTableIndices()... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2aae5ba15d07e9aa37ff9b03ad0024c0707068f5;p=clang Recommit r183298+r183300 'Get rid of VTableContext::ComputeMethodVTableIndices() and VTableContext::getNumVirtualFunctionPointers()' In r183298, I've used llvm::SmallPtrSet<..., 8> instead of llvm::SmallVector<..., 8> for NewVirtualFunctionsTy by mistake. This only manifested when a class had more than 8 virtual functions, which wasn't covered by unit-tests git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183310 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h index bcbe8754ea..efd388dcfd 100644 --- a/include/clang/AST/VTableBuilder.h +++ b/include/clang/AST/VTableBuilder.h @@ -286,10 +286,6 @@ private: VTableLayoutMapTy; VTableLayoutMapTy VTableLayouts; - /// NumVirtualFunctionPointers - Contains the number of virtual function - /// pointers in the vtable for a given record decl. - llvm::DenseMap NumVirtualFunctionPointers; - typedef std::pair ClassPairTy; @@ -305,8 +301,6 @@ private: /// Thunks - Contains all thunks that a given method decl will need. ThunksMapTy Thunks; - void ComputeMethodVTableIndices(const CXXRecordDecl *RD); - /// ComputeVTableRelatedInformation - Compute and store all vtable related /// information (vtable layout, vbase offset offsets, thunks etc) for the /// given record decl. @@ -352,10 +346,6 @@ public: return &I->second; } - /// getNumVirtualFunctionPointers - Return the number of virtual function - /// pointers in the vtable for a given record decl. - uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); - /// getMethodVTableIndex - Return the index (relative to the vtable address /// point) where the function pointer for the given virtual function is /// stored. diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index 4f28c77b75..65e11b7af8 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -787,6 +787,8 @@ public: typedef llvm::DenseMap AddressPointsMapTy; + typedef llvm::DenseMap MethodVTableIndicesTy; + private: /// VTables - Global vtable information. VTableContext &VTables; @@ -859,7 +861,11 @@ private: /// MethodInfoMap - The information for all methods in the vtable we're /// currently building. MethodInfoMapTy MethodInfoMap; - + + /// MethodVTableIndices - Contains the index (relative to the vtable address + /// point) where the function pointer for a virtual function is stored. + MethodVTableIndicesTy MethodVTableIndices; + typedef llvm::DenseMap VTableThunksMapTy; /// VTableThunks - The thunks by vtable index in the vtable currently being @@ -1022,6 +1028,14 @@ public: return AddressPoints; } + MethodVTableIndicesTy::const_iterator vtable_indices_begin() const { + return MethodVTableIndices.begin(); + } + + MethodVTableIndicesTy::const_iterator vtable_indices_end() const { + return MethodVTableIndices.end(); + } + /// getNumVTableComponents - Return the number of components in the vtable /// currently built. uint64_t getNumVTableComponents() const { @@ -1437,6 +1451,15 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, const CXXRecordDecl *FirstBaseInPrimaryBaseChain, CharUnits FirstBaseOffsetInLayoutClass, PrimaryBasesSetVectorTy &PrimaryBases) { + // Itanium C++ ABI 2.5.2: + // The order of the virtual function pointers in a virtual table is the + // order of declaration of the corresponding member functions in the class. + // + // There is an entry for any virtual function declared in a class, + // whether it is a new function or overrides a base class function, + // unless it overrides a function from the primary base, and conversion + // between their return types does not require an adjustment. + const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); @@ -1474,6 +1497,11 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, llvm_unreachable("Found a duplicate primary base!"); } + const CXXDestructorDecl *ImplicitVirtualDtor = 0; + + typedef llvm::SmallVector NewVirtualFunctionsTy; + NewVirtualFunctionsTy NewVirtualFunctions; + // Now go through all virtual member functions and add them. for (CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) { @@ -1539,6 +1567,33 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, } } + if (const CXXDestructorDecl *DD = dyn_cast(MD)) { + if (MD->isImplicit()) { + // Itanium C++ ABI 2.5.2: + // If a class has an implicitly-defined virtual destructor, + // its entries come after the declared virtual function pointers. + + assert(!ImplicitVirtualDtor && + "Did already see an implicit virtual dtor!"); + ImplicitVirtualDtor = DD; + continue; + } + } + + NewVirtualFunctions.push_back(MD); + } + + if (ImplicitVirtualDtor) + NewVirtualFunctions.push_back(ImplicitVirtualDtor); + + for (NewVirtualFunctionsTy::const_iterator I = NewVirtualFunctions.begin(), + E = NewVirtualFunctions.end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(MD, Base.getBaseOffset()); + // Insert the method info for this method. MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, Components.size()); @@ -1555,7 +1610,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD)); continue; } - + // Check if this overrider needs a return adjustment. // We don't want to do this for pure virtual member functions. BaseOffset ReturnAdjustmentOffset; @@ -1640,11 +1695,34 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, Base.getBase(), OffsetInLayoutClass, PrimaryBases); + const CXXRecordDecl *RD = Base.getBase(); + if (RD == MostDerivedClass) { + assert(MethodVTableIndices.empty()); + for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), + E = MethodInfoMap.end(); I != E; ++I) { + const CXXMethodDecl *MD = I->first; + const MethodInfo &MI = I->second; + if (const CXXDestructorDecl *DD = dyn_cast(MD)) { + // FIXME: Should probably add a layer of abstraction for vtable generation. + if (!isMicrosoftABI()) { + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] + = MI.VTableIndex - AddressPoint; + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] + = MI.VTableIndex + 1 - AddressPoint; + } else { + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] + = MI.VTableIndex - AddressPoint; + } + } else { + MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint; + } + } + } + // Compute 'this' pointer adjustments. ComputeThisAdjustments(); // Add all address points. - const CXXRecordDecl *RD = Base.getBase(); while (true) { AddressPoints.insert(std::make_pair( BaseSubobject(RD, OffsetInLayoutClass), @@ -2136,16 +2214,19 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { if (const CXXDestructorDecl *DD = dyn_cast(MD)) { // FIXME: Should add a layer of abstraction for vtable generation. if (!isMicrosoftABI()) { - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] - = MethodName + " [complete]"; - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] - = MethodName + " [deleting]"; + GlobalDecl GD(DD, Dtor_Complete); + assert(MethodVTableIndices.count(GD)); + uint64_t VTableIndex = MethodVTableIndices[GD]; + IndicesMap[VTableIndex] = MethodName + " [complete]"; + IndicesMap[VTableIndex + 1] = MethodName + " [deleting]"; } else { - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] - = MethodName + " [scalar deleting]"; + GlobalDecl GD(DD, Dtor_Deleting); + assert(MethodVTableIndices.count(GD)); + IndicesMap[MethodVTableIndices[GD]] = MethodName + " [scalar deleting]"; } } else { - IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName; + assert(MethodVTableIndices.count(MD)); + IndicesMap[MethodVTableIndices[MD]] = MethodName; } } @@ -2160,7 +2241,7 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { uint64_t VTableIndex = I->first; const std::string &MethodName = I->second; - Out << llvm::format(" %4" PRIu64 " | ", VTableIndex) << MethodName + Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n'; } } @@ -2199,153 +2280,6 @@ VTableContext::~VTableContext() { llvm::DeleteContainerSeconds(VTableLayouts); } -static void -CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, - VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (!PrimaryBase) - return; - - CollectPrimaryBases(PrimaryBase, Context, PrimaryBases); - - if (!PrimaryBases.insert(PrimaryBase)) - llvm_unreachable("Found a duplicate primary base!"); -} - -void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) { - - // Itanium C++ ABI 2.5.2: - // The order of the virtual function pointers in a virtual table is the - // order of declaration of the corresponding member functions in the class. - // - // There is an entry for any virtual function declared in a class, - // whether it is a new function or overrides a base class function, - // unless it overrides a function from the primary base, and conversion - // between their return types does not require an adjustment. - - int64_t CurrentIndex = 0; - - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (PrimaryBase) { - assert(PrimaryBase->isCompleteDefinition() && - "Should have the definition decl of the primary base!"); - - // Since the record decl shares its vtable pointer with the primary base - // we need to start counting at the end of the primary base's vtable. - CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); - } - - // Collect all the primary bases, so we can check whether methods override - // a method from the base. - VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; - CollectPrimaryBases(RD, Context, PrimaryBases); - - const CXXDestructorDecl *ImplicitVirtualDtor = 0; - - for (CXXRecordDecl::method_iterator i = RD->method_begin(), - e = RD->method_end(); i != e; ++i) { - const CXXMethodDecl *MD = *i; - - // We only want virtual methods. - if (!MD->isVirtual()) - continue; - - // Check if this method overrides a method in the primary base. - if (const CXXMethodDecl *OverriddenMD = - FindNearestOverriddenMethod(MD, PrimaryBases)) { - // Check if converting from the return type of the method to the - // return type of the overridden method requires conversion. - if (ComputeReturnAdjustmentBaseOffset(Context, MD, - OverriddenMD).isEmpty()) { - // This index is shared between the index in the vtable of the primary - // base class. - if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - const CXXDestructorDecl *OverriddenDD = - cast(OverriddenMD); - - if (!isMicrosoftABI()) { - // Add both the complete and deleting entries. - MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); - } else { - // Add the scalar deleting destructor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); - } - } else { - MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD); - } - - // We don't need to add an entry for this method. - continue; - } - } - - if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - if (MD->isImplicit()) { - assert(!ImplicitVirtualDtor && - "Did already see an implicit virtual dtor!"); - ImplicitVirtualDtor = DD; - continue; - } - - if (!isMicrosoftABI()) { - // Add the complete dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; - - // Add the deleting dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; - } else { - // Add the scalar deleting dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; - } - } else { - // Add the entry. - MethodVTableIndices[MD] = CurrentIndex++; - } - } - - if (ImplicitVirtualDtor) { - // Itanium C++ ABI 2.5.2: - // If a class has an implicitly-defined virtual destructor, - // its entries come after the declared virtual function pointers. - - if (isMicrosoftABI()) { - ErrorUnsupported("implicit virtual destructor in the Microsoft ABI", - ImplicitVirtualDtor->getLocation()); - } - - // Add the complete dtor. - MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = - CurrentIndex++; - - // Add the deleting dtor. - MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] = - CurrentIndex++; - } - - NumVirtualFunctionPointers[RD] = CurrentIndex; -} - -uint64_t VTableContext::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { - llvm::DenseMap::iterator I = - NumVirtualFunctionPointers.find(RD); - if (I != NumVirtualFunctionPointers.end()) - return I->second; - - ComputeMethodVTableIndices(RD); - - I = NumVirtualFunctionPointers.find(RD); - assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!"); - return I->second; -} - uint64_t VTableContext::getMethodVTableIndex(GlobalDecl GD) { MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); if (I != MethodVTableIndices.end()) @@ -2353,7 +2287,7 @@ uint64_t VTableContext::getMethodVTableIndex(GlobalDecl GD) { const CXXRecordDecl *RD = cast(GD.getDecl())->getParent(); - ComputeMethodVTableIndices(RD); + ComputeVTableRelatedInformation(RD); I = MethodVTableIndices.find(GD); assert(I != MethodVTableIndices.end() && "Did not find index!"); @@ -2415,6 +2349,9 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { /*MostDerivedClassIsVirtual=*/0, RD); Entry = CreateVTableLayout(Builder); + MethodVTableIndices.insert(Builder.vtable_indices_begin(), + Builder.vtable_indices_end()); + // Add the known thunks. Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());