@@ -1147,11 +1147,38 @@ void ItaniumVTableBuilder::ComputeThisAdjustments() {
1147
1147
continue ;
1148
1148
1149
1149
// Add it.
1150
- VTableThunks[VTableIndex].This = ThisAdjustment;
1150
+ auto SetThisAdjustmentThunk = [&](uint64_t Idx) {
1151
+ // If a this pointer adjustment is required, record the method that
1152
+ // created the vtable entry. MD is not necessarily the method that
1153
+ // created the entry since derived classes overwrite base class
1154
+ // information in MethodInfoMap, hence findOriginalMethodInMap is called
1155
+ // here.
1156
+ //
1157
+ // For example, in the following class hierarchy, if MD = D1::m and
1158
+ // Overrider = D2:m, the original method that created the entry is B0:m,
1159
+ // which is what findOriginalMethodInMap(MD) returns:
1160
+ //
1161
+ // struct B0 { int a; virtual void m(); };
1162
+ // struct D0 : B0 { int a; void m() override; };
1163
+ // struct D1 : B0 { int a; void m() override; };
1164
+ // struct D2 : D0, D1 { int a; void m() override; };
1165
+ //
1166
+ // We need to record the method because we cannot
1167
+ // call findOriginalMethod to find the method that created the entry if
1168
+ // the method in the entry requires adjustment.
1169
+ //
1170
+ // Do not set ThunkInfo::Method if Idx is already in VTableThunks. This
1171
+ // can happen when covariant return adjustment is required too.
1172
+ if (!VTableThunks.count (Idx))
1173
+ VTableThunks[Idx].Method = VTables.findOriginalMethodInMap (MD);
1174
+ VTableThunks[Idx].This = ThisAdjustment;
1175
+ };
1176
+
1177
+ SetThisAdjustmentThunk (VTableIndex);
1151
1178
1152
1179
if (isa<CXXDestructorDecl>(MD)) {
1153
1180
// Add an adjustment for the deleting destructor as well.
1154
- VTableThunks[ VTableIndex + 1 ]. This = ThisAdjustment ;
1181
+ SetThisAdjustmentThunk ( VTableIndex + 1 ) ;
1155
1182
}
1156
1183
}
1157
1184
@@ -1509,6 +1536,8 @@ void ItaniumVTableBuilder::AddMethods(
1509
1536
FindNearestOverriddenMethod (MD, PrimaryBases)) {
1510
1537
if (ComputeReturnAdjustmentBaseOffset (Context, MD,
1511
1538
OverriddenMD).isEmpty ()) {
1539
+ VTables.setOriginalMethod (MD, OverriddenMD);
1540
+
1512
1541
// Replace the method info of the overridden method with our own
1513
1542
// method.
1514
1543
assert (MethodInfoMap.count (OverriddenMD) &&
@@ -1615,6 +1644,13 @@ void ItaniumVTableBuilder::AddMethods(
1615
1644
ReturnAdjustment ReturnAdjustment =
1616
1645
ComputeReturnAdjustment (ReturnAdjustmentOffset);
1617
1646
1647
+ // If a return adjustment is required, record the method that created the
1648
+ // vtable entry. We need to record the method because we cannot call
1649
+ // findOriginalMethod to find the method that created the entry if the
1650
+ // method in the entry requires adjustment.
1651
+ if (!ReturnAdjustment.isEmpty ())
1652
+ VTableThunks[Components.size ()].Method = MD;
1653
+
1618
1654
AddMethod (Overrider.Method , ReturnAdjustment);
1619
1655
}
1620
1656
}
@@ -1890,11 +1926,32 @@ void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
1890
1926
}
1891
1927
}
1892
1928
1929
+ static void printThunkMethod (const ThunkInfo &Info, raw_ostream &Out) {
1930
+ if (Info.Method ) {
1931
+ std::string Str =
1932
+ PredefinedExpr::ComputeName (PredefinedIdentKind::PrettyFunctionNoVirtual,
1933
+ Info.Method );
1934
+ Out << " method: " << Str;
1935
+ }
1936
+ }
1937
+
1893
1938
// / dumpLayout - Dump the vtable layout.
1894
1939
void ItaniumVTableBuilder::dumpLayout (raw_ostream &Out) {
1895
1940
// FIXME: write more tests that actually use the dumpLayout output to prevent
1896
1941
// ItaniumVTableBuilder regressions.
1897
1942
1943
+ Out << " Original map\n " ;
1944
+
1945
+ for (const auto &P : VTables.getOriginalMethodMap ()) {
1946
+ std::string Str0 =
1947
+ PredefinedExpr::ComputeName (PredefinedIdentKind::PrettyFunctionNoVirtual,
1948
+ P.first );
1949
+ std::string Str1 =
1950
+ PredefinedExpr::ComputeName (PredefinedIdentKind::PrettyFunctionNoVirtual,
1951
+ P.second );
1952
+ Out << " " << Str0 << " -> " << Str1 << " \n " ;
1953
+ }
1954
+
1898
1955
if (isBuildingConstructorVTable ()) {
1899
1956
Out << " Construction vtable for ('" ;
1900
1957
MostDerivedClass->printQualifiedName (Out);
@@ -1978,6 +2035,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
1978
2035
}
1979
2036
1980
2037
Out << ' ]' ;
2038
+ printThunkMethod (Thunk, Out);
1981
2039
}
1982
2040
1983
2041
// If this function pointer has a 'this' pointer adjustment, dump it.
@@ -1991,6 +2049,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
1991
2049
}
1992
2050
1993
2051
Out << ' ]' ;
2052
+ printThunkMethod (Thunk, Out);
1994
2053
}
1995
2054
}
1996
2055
@@ -2027,6 +2086,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
2027
2086
2028
2087
Out << ' ]' ;
2029
2088
}
2089
+ printThunkMethod (Thunk, Out);
2030
2090
}
2031
2091
2032
2092
break ;
@@ -2125,7 +2185,6 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
2125
2185
2126
2186
ThunkInfoVectorTy ThunksVector = Thunks[MD];
2127
2187
llvm::sort (ThunksVector, [](const ThunkInfo &LHS, const ThunkInfo &RHS) {
2128
- assert (LHS.Method == nullptr && RHS.Method == nullptr );
2129
2188
return std::tie (LHS.This , LHS.Return ) < std::tie (RHS.This , RHS.Return );
2130
2189
});
2131
2190
@@ -2314,6 +2373,35 @@ ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
2314
2373
return I->second ;
2315
2374
}
2316
2375
2376
+ GlobalDecl ItaniumVTableContext::findOriginalMethod (GlobalDecl GD) {
2377
+ const auto *MD = cast<CXXMethodDecl>(GD.getDecl ());
2378
+ computeVTableRelatedInformation (MD->getParent ());
2379
+ const auto *OriginalMD = findOriginalMethodInMap (MD);
2380
+
2381
+ if (const auto *DD = dyn_cast<CXXDestructorDecl>(OriginalMD))
2382
+ return GlobalDecl (DD, GD.getDtorType ());
2383
+ return OriginalMD;
2384
+ }
2385
+
2386
+ const CXXMethodDecl *
2387
+ ItaniumVTableContext::findOriginalMethodInMap (const CXXMethodDecl *MD) const {
2388
+ // Traverse the chain of virtual methods until we find the method that added
2389
+ // the v-table slot.
2390
+ while (true ) {
2391
+ auto I = OriginalMethodMap.find (MD);
2392
+
2393
+ // MD doesn't exist in OriginalMethodMap, so it must be the method we are
2394
+ // looking for.
2395
+ if (I == OriginalMethodMap.end ())
2396
+ break ;
2397
+
2398
+ // Set MD to the overridden method.
2399
+ MD = I->second ;
2400
+ }
2401
+
2402
+ return MD;
2403
+ }
2404
+
2317
2405
static std::unique_ptr<VTableLayout>
2318
2406
CreateVTableLayout (const ItaniumVTableBuilder &Builder) {
2319
2407
SmallVector<VTableLayout::VTableThunkTy, 1 >
0 commit comments