Skip to content

Commit 6466bb8

Browse files
authored
Merge pull request #63628 from hyp/eng/vtable5
[interop][SwiftToCxx] fix vtable offset computation & dispatch virtual Swift methods using a relative offset into the vtable for classes deriving from resilient classes
2 parents 55d0bbe + 45eb846 commit 6466bb8

11 files changed

+296
-46
lines changed

include/swift/IRGen/IRABIDetailsProvider.h

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ class IRABIDetailsProvider {
255255
Direct,
256256
/// An indirect call that can be made via a static offset in a vtable.
257257
IndirectVTableStaticOffset,
258+
/// An indirect call that should be made via an offset relative to
259+
/// external base value in a vtable.
260+
IndirectVTableRelativeOffset,
258261
/// The call should be made via the provided thunk function.
259262
Thunk
260263
};
@@ -268,44 +271,73 @@ class IRABIDetailsProvider {
268271
}
269272

270273
static MethodDispatchInfo indirectVTableStaticOffset(
271-
size_t bitOffset, Optional<PointerAuthDiscriminator> discriminator) {
272-
return MethodDispatchInfo(Kind::IndirectVTableStaticOffset, bitOffset, "",
274+
size_t offset, Optional<PointerAuthDiscriminator> discriminator) {
275+
return MethodDispatchInfo(Kind::IndirectVTableStaticOffset, offset, "",
273276
discriminator);
274277
}
275278

279+
static MethodDispatchInfo indirectVTableRelativeOffset(
280+
size_t offset, std::string symbolName,
281+
Optional<PointerAuthDiscriminator> discriminator) {
282+
return MethodDispatchInfo(Kind::IndirectVTableRelativeOffset, offset,
283+
symbolName, discriminator);
284+
}
285+
276286
static MethodDispatchInfo thunk(std::string thunkName) {
277287
return MethodDispatchInfo(Kind::Thunk, 0, thunkName);
278288
}
279289

280290
Kind getKind() const { return kind; }
281-
size_t getStaticBitOffset() const {
291+
292+
/// Return the byte offset into the vtable from which the method pointer
293+
/// should be loaded.
294+
size_t getStaticOffset() const {
282295
assert(kind == Kind::IndirectVTableStaticOffset);
283-
return bitOffset;
296+
return offset;
284297
}
285298
Optional<PointerAuthDiscriminator> getPointerAuthDiscriminator() const {
286-
assert(kind == Kind::IndirectVTableStaticOffset);
299+
assert(kind == Kind::IndirectVTableStaticOffset ||
300+
kind == Kind::IndirectVTableRelativeOffset);
287301
return discriminator;
288302
}
289303
StringRef getThunkSymbolName() const {
290304
assert(kind == Kind::Thunk);
291-
return thunkName;
305+
return symbolName;
306+
}
307+
308+
/// Return the byte offset relative to base offset value into the vtable
309+
/// from which the method pointer should be loaded.
310+
size_t getRelativeOffset() const {
311+
assert(kind == Kind::IndirectVTableRelativeOffset);
312+
return offset;
313+
}
314+
315+
/// Return the external symbol from which the relative base offset should be
316+
/// loaded.
317+
StringRef getBaseOffsetSymbolName() const {
318+
assert(kind == Kind::IndirectVTableRelativeOffset);
319+
return symbolName;
292320
}
293321

294322
private:
295-
MethodDispatchInfo(Kind kind, size_t bitOffset, std::string thunkName = "",
323+
MethodDispatchInfo(Kind kind, size_t offset, std::string symbolName = "",
296324
Optional<PointerAuthDiscriminator> discriminator = None)
297-
: kind(kind), bitOffset(bitOffset), thunkName(thunkName),
325+
: kind(kind), offset(offset), symbolName(symbolName),
298326
discriminator(discriminator) {}
299327

300328
Kind kind;
301-
size_t bitOffset;
302-
std::string thunkName;
329+
size_t offset;
330+
std::string symbolName;
303331
Optional<PointerAuthDiscriminator> discriminator;
304332
};
305333

306334
Optional<MethodDispatchInfo>
307335
getMethodDispatchInfo(const AbstractFunctionDecl *funcDecl);
308336

337+
/// Returns the type of the base offset value located at the specific class
338+
/// base offset symbol.
339+
Type getClassBaseOffsetSymbolType() const;
340+
309341
private:
310342
std::unique_ptr<IRABIDetailsProviderImpl> impl;
311343
};

lib/IRGen/IRABIDetailsProvider.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,24 @@ class IRABIDetailsProviderImpl {
253253
case ClassMetadataLayout::MethodInfo::Kind::Offset:
254254
if (mi->TheOffset.isStatic()) {
255255
return MethodDispatchInfo::indirectVTableStaticOffset(
256-
/*bitOffset=*/mi->TheOffset.getStaticOffset().getValue(),
256+
/*offset=*/mi->TheOffset.getStaticOffset().getValue(),
257257
getMethodPointerAuthInfo(funcDecl, silDecl));
258258
}
259-
return {};
259+
assert(mi->TheOffset.isDynamic());
260+
return MethodDispatchInfo::indirectVTableRelativeOffset(
261+
/*offset=*/mi->TheOffset.getRelativeOffset().getValue(),
262+
/*symbolName=*/
263+
LinkEntity::forClassMetadataBaseOffset(parentClass).mangleAsString(),
264+
getMethodPointerAuthInfo(funcDecl, silDecl));
260265
}
261266
llvm_unreachable("invalid kind");
262267
}
263268

269+
Type getClassBaseOffsetSymbolType() const {
270+
return *getPrimitiveTypeFromLLVMType(
271+
silMod->getASTContext(), IGM.ClassMetadataBaseOffsetTy->elements()[0]);
272+
}
273+
264274
Lowering::TypeConverter typeConverter;
265275
// Default silOptions are sufficient, as we don't need to generated SIL.
266276
SILOptions silOpts;
@@ -470,3 +480,7 @@ IRABIDetailsProvider::getMethodDispatchInfo(
470480
const AbstractFunctionDecl *funcDecl) {
471481
return impl->getMethodDispatchInfo(funcDecl);
472482
}
483+
484+
Type IRABIDetailsProvider::getClassBaseOffsetSymbolType() const {
485+
return impl->getClassBaseOffsetSymbolType();
486+
}

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "ClangSyntaxPrinter.h"
14+
#include "PrimitiveTypeMapping.h"
1415
#include "swift/ABI/MetadataValues.h"
1516
#include "swift/AST/ASTContext.h"
1617
#include "swift/AST/Decl.h"
@@ -424,3 +425,13 @@ void ClangSyntaxPrinter::printSymbolUSRAttribute(const ValueDecl *D) const {
424425
return;
425426
os << " SWIFT_SYMBOL(\"" << result << "\")";
426427
}
428+
429+
void ClangSyntaxPrinter::printKnownCType(
430+
Type t, PrimitiveTypeMapping &typeMapping) const {
431+
auto info =
432+
typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal());
433+
assert(info.has_value() && "not a known type");
434+
os << info->name;
435+
if (info->canBeNullable)
436+
os << " _Null_unspecified";
437+
}

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
#ifndef SWIFT_PRINTASCLANG_CLANGSYNTAXPRINTER_H
1414
#define SWIFT_PRINTASCLANG_CLANGSYNTAXPRINTER_H
1515

16-
#include "swift/IRGen/GenericRequirement.h"
16+
#include "swift/AST/Type.h"
1717
#include "swift/Basic/LLVM.h"
1818
#include "swift/ClangImporter/ClangImporter.h"
19+
#include "swift/IRGen/GenericRequirement.h"
1920
#include "llvm/ADT/StringRef.h"
2021
#include "llvm/Support/raw_ostream.h"
2122

@@ -25,6 +26,7 @@ class CanGenericSignature;
2526
class GenericTypeParamType;
2627
class ModuleDecl;
2728
class NominalTypeDecl;
29+
class PrimitiveTypeMapping;
2830

2931
namespace cxx_synthesis {
3032

@@ -225,6 +227,9 @@ class ClangSyntaxPrinter {
225227
/// on the generated declaration.
226228
void printSymbolUSRAttribute(const ValueDecl *D) const;
227229

230+
/// Print the given **known** type as a C type.
231+
void printKnownCType(Type t, PrimitiveTypeMapping &typeMapping) const;
232+
228233
protected:
229234
raw_ostream &os;
230235
};

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,21 @@ class DeclAndTypePrinter::Implementation
14431443
FD, funcABI, resultTy, funcTy, dispatchInfo->getThunkSymbolName(),
14441444
"dispatch thunk for");
14451445
assert(!thunkRepresentation.isUnsupported());
1446+
} else if (dispatchInfo->getKind() ==
1447+
IRABIDetailsProvider::MethodDispatchInfo::Kind::
1448+
IndirectVTableRelativeOffset) {
1449+
// Emit the C signature for the class metadata base offset.
1450+
owningPrinter.interopContext.runIfStubForDeclNotEmitted(
1451+
dispatchInfo->getBaseOffsetSymbolName(), [&] {
1452+
auto baseClassOffsetType =
1453+
owningPrinter.interopContext.getIrABIDetails()
1454+
.getClassBaseOffsetSymbolType();
1455+
os << "SWIFT_EXTERN ";
1456+
ClangSyntaxPrinter(os).printKnownCType(
1457+
baseClassOffsetType, owningPrinter.typeMapping);
1458+
os << ' ' << dispatchInfo->getBaseOffsetSymbolName()
1459+
<< "; // class metadata base offset\n";
1460+
});
14461461
}
14471462
}
14481463
}

lib/PrintAsClang/PrintClangClassType.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ void ClangClassTypePrinter::printClassTypeDecl(
5050
ClangSyntaxPrinter(baseQualNameOS)
5151
.printModuleNamespaceQualifiersIfNeeded(parentClass->getModuleContext(),
5252
typeDecl->getModuleContext());
53-
if (!baseQualNameOS.str().empty())
54-
baseQualNameOS << "::";
5553
baseQualNameOS << baseNameOS.str();
5654
} else {
5755
baseClassName = "RefCountedClass";

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11051105
case DispatchKindTy::Direct:
11061106
break;
11071107
case DispatchKindTy::IndirectVTableStaticOffset:
1108+
case DispatchKindTy::IndirectVTableRelativeOffset:
11081109
os << "void ***selfPtr_ = reinterpret_cast<void ***>( "
11091110
"::swift::_impl::_impl_RefCountedClass::getOpaquePointer(*this));"
11101111
"\n";
@@ -1126,8 +1127,14 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11261127
os << " func;\n";
11271128
os << "};\n";
11281129
os << "FTypeAddress *fptrptr_ = reinterpret_cast<FTypeAddress *>(vtable_ "
1129-
"+ "
1130-
<< (dispatchInfo->getStaticBitOffset() / 8) << ");\n";
1130+
"+ ";
1131+
if (dispatchInfo->getKind() == DispatchKindTy::IndirectVTableStaticOffset)
1132+
os << dispatchInfo->getStaticOffset();
1133+
else
1134+
os << '(' << cxx_synthesis::getCxxImplNamespaceName()
1135+
<< "::" << dispatchInfo->getBaseOffsetSymbolName() << " + "
1136+
<< dispatchInfo->getRelativeOffset() << ')';
1137+
os << " / sizeof(void *));\n";
11311138
indirectFunctionVar = StringRef("fptrptr_->func");
11321139
break;
11331140
case DispatchKindTy::Thunk:

lib/PrintAsClang/PrintSwiftToClangCoreScaffold.cpp

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,14 @@
2323

2424
using namespace swift;
2525

26-
static void printKnownCType(Type t, PrimitiveTypeMapping &typeMapping,
27-
raw_ostream &os) {
28-
auto info =
29-
typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal());
30-
assert(info.has_value() && "not a known type");
31-
os << info->name;
32-
if (info->canBeNullable)
33-
os << " _Null_unspecified";
34-
}
35-
3626
static void printKnownStruct(
3727
PrimitiveTypeMapping &typeMapping, raw_ostream &os, StringRef name,
3828
const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) {
3929
assert(typeRecord.getMembers().size() > 1);
4030
os << "struct " << name << " {\n";
4131
for (const auto &ty : llvm::enumerate(typeRecord.getMembers())) {
4232
os << " ";
43-
printKnownCType(ty.value(), typeMapping, os);
33+
ClangSyntaxPrinter(os).printKnownCType(ty.value(), typeMapping);
4434
os << " _" << ty.index() << ";\n";
4535
}
4636
os << "};\n";
@@ -51,7 +41,8 @@ static void printKnownTypedef(
5141
const IRABIDetailsProvider::TypeRecordABIRepresentation &typeRecord) {
5242
assert(typeRecord.getMembers().size() == 1);
5343
os << "typedef ";
54-
printKnownCType(typeRecord.getMembers()[0], typeMapping, os);
44+
ClangSyntaxPrinter(os).printKnownCType(typeRecord.getMembers()[0],
45+
typeMapping);
5546
os << " " << name << ";\n";
5647
}
5748

0 commit comments

Comments
 (0)