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

llvm-svn: 183310
This commit is contained in:
Timur Iskhodzhanov 2013-06-05 14:05:50 +00:00
parent b1347cd50a
commit 05e3670498
2 changed files with 96 additions and 169 deletions

View File

@ -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<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
typedef std::pair<const CXXRecordDecl *,
const CXXRecordDecl *> 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.

View File

@ -787,6 +787,8 @@ public:
typedef llvm::DenseMap<BaseSubobject, uint64_t>
AddressPointsMapTy;
typedef llvm::DenseMap<GlobalDecl, int64_t> 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<uint64_t, ThunkInfo> 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<const CXXMethodDecl *, 8> 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<CXXDestructorDecl>(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<CXXDestructorDecl>(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<CXXDestructorDecl>(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<CXXDestructorDecl>(MD)) {
const CXXDestructorDecl *OverriddenDD =
cast<CXXDestructorDecl>(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<CXXDestructorDecl>(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<const CXXRecordDecl *, uint64_t>::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<CXXMethodDecl>(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());