Skip to content

Commit d428526

Browse files
authored
Merge pull request #13845 from slavapestov/class-dispatch-thunks-irgen
Generate class dispatch thunks in IRGen
2 parents aed3c47 + 9b0f6fc commit d428526

15 files changed

+209
-224
lines changed

include/swift/SIL/SILDeclRef.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,6 @@ struct SILDeclRef {
213213
enum class ManglingKind {
214214
Default,
215215
DynamicThunk,
216-
SwiftDispatchThunk,
217216
};
218217

219218
/// Produce a mangled form of this constant.

lib/IRGen/GenClass.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/IRGen/Linking.h"
3232
#include "swift/SIL/SILModule.h"
3333
#include "swift/SIL/SILType.h"
34+
#include "swift/SIL/SILVTableVisitor.h"
3435
#include "llvm/ADT/SmallString.h"
3536
#include "llvm/IR/CallSite.h"
3637
#include "llvm/IR/DerivedTypes.h"
@@ -1019,6 +1020,36 @@ void IRGenModule::emitClassDecl(ClassDecl *D) {
10191020

10201021
emitNestedTypeDecls(D->getMembers());
10211022
emitFieldMetadataRecord(D);
1023+
1024+
// If the class is resilient, emit dispatch thunks.
1025+
if (isResilient(D, ResilienceExpansion::Minimal)) {
1026+
struct ThunkEmitter : public SILVTableVisitor<ThunkEmitter> {
1027+
IRGenModule &IGM;
1028+
ClassDecl *D;
1029+
1030+
ThunkEmitter(IRGenModule &IGM, ClassDecl *D)
1031+
: IGM(IGM), D(D) {
1032+
addVTableEntries(D);
1033+
}
1034+
1035+
void addMethodOverride(SILDeclRef baseRef, SILDeclRef declRef) {}
1036+
1037+
void addMethod(SILDeclRef member) {
1038+
auto *func = cast<AbstractFunctionDecl>(member.getDecl());
1039+
if (func->getDeclContext() == D &&
1040+
func->getEffectiveAccess() >= AccessLevel::Public) {
1041+
IGM.emitDispatchThunk(member);
1042+
}
1043+
}
1044+
1045+
void addPlaceholder(MissingMemberDecl *m) {
1046+
assert(m->getNumberOfVTableEntries() == 0
1047+
&& "Should not be emitting class with missing members");
1048+
}
1049+
};
1050+
1051+
ThunkEmitter emitter(*this, D);
1052+
}
10221053
}
10231054

10241055
namespace {

lib/IRGen/GenMeta.cpp

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4516,7 +4516,27 @@ llvm::Value *irgen::emitClassHeapMetadataRefForMetatype(IRGenFunction &IGF,
45164516
return call;
45174517
}
45184518

4519-
/// Load the correct virtual function for the given class method.
4519+
FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
4520+
llvm::Value *metadata,
4521+
SILDeclRef method,
4522+
CanSILFunctionType methodType) {
4523+
Signature signature = IGF.IGM.getSignature(methodType);
4524+
4525+
auto classDecl = cast<ClassDecl>(method.getDecl()->getDeclContext());
4526+
4527+
// Find the vtable entry we're interested in.
4528+
auto methodInfo =
4529+
IGF.IGM.getClassMetadataLayout(classDecl).getMethodInfo(IGF, method);
4530+
auto offset = methodInfo.getOffset();
4531+
4532+
auto slot = IGF.emitAddressAtOffset(metadata, offset,
4533+
signature.getType()->getPointerTo(),
4534+
IGF.IGM.getPointerAlignment());
4535+
auto fnPtr = IGF.emitInvariantLoad(slot);
4536+
4537+
return FunctionPointer(fnPtr, signature);
4538+
}
4539+
45204540
FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
45214541
llvm::Value *base,
45224542
SILType baseType,
@@ -4565,22 +4585,7 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
45654585
}
45664586
}
45674587

4568-
// Use the type of the method we were type-checked against, not the
4569-
// type of the overridden method.
4570-
auto sig = IGF.IGM.getSignature(methodType);
4571-
4572-
auto declaringClass = cast<ClassDecl>(overridden.getDecl()->getDeclContext());
4573-
4574-
auto methodInfo =
4575-
IGF.IGM.getClassMetadataLayout(declaringClass).getMethodInfo(IGF, overridden);
4576-
auto offset = methodInfo.getOffset();
4577-
4578-
auto slot = IGF.emitAddressAtOffset(metadata, offset,
4579-
sig.getType()->getPointerTo(),
4580-
IGF.IGM.getPointerAlignment());
4581-
auto fnPtr = IGF.emitInvariantLoad(slot);
4582-
4583-
return FunctionPointer(fnPtr, sig);
4588+
return emitVirtualMethodValue(IGF, metadata, overridden, methodType);
45844589
}
45854590

45864591
//===----------------------------------------------------------------------===//

lib/IRGen/GenMeta.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ namespace irgen {
223223
SILType objectType,
224224
bool suppressCast = false);
225225

226+
/// Given a metadata pointer, emit the callee for the given method.
227+
FunctionPointer emitVirtualMethodValue(IRGenFunction &IGF,
228+
llvm::Value *metadata,
229+
SILDeclRef method,
230+
CanSILFunctionType methodType);
231+
226232
/// Given an instance pointer (or, for a static method, a class
227233
/// pointer), emit the callee for the given method.
228234
FunctionPointer emitVirtualMethodValue(IRGenFunction &IGF,

lib/IRGen/GenThunk.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
#include "Callee.h"
2020
#include "Explosion.h"
2121
#include "GenDecl.h"
22+
#include "GenMeta.h"
2223
#include "GenOpaque.h"
2324
#include "GenProto.h"
2425
#include "IRGenFunction.h"
2526
#include "IRGenModule.h"
27+
#include "MetadataLayout.h"
2628
#include "ProtocolInfo.h"
2729
#include "Signature.h"
2830
#include "swift/IRGen/Linking.h"
@@ -52,11 +54,43 @@ IRGenModule::getAddrOfDispatchThunk(SILDeclRef declRef,
5254

5355
static FunctionPointer lookupMethod(IRGenFunction &IGF,
5456
SILDeclRef declRef) {
55-
// Find the witness table.
56-
llvm::Value *wtable = (IGF.CurFn->arg_end() - 1);
57+
auto *decl = cast<AbstractFunctionDecl>(declRef.getDecl());
5758

58-
// Find the witness we're interested in.
59-
return emitWitnessMethodValue(IGF, wtable, declRef);
59+
// Protocol case.
60+
if (isa<ProtocolDecl>(decl->getDeclContext())) {
61+
// Find the witness table.
62+
llvm::Value *wtable = (IGF.CurFn->arg_end() - 1);
63+
64+
// Find the witness we're interested in.
65+
return emitWitnessMethodValue(IGF, wtable, declRef);
66+
}
67+
68+
// Class case.
69+
auto funcTy = IGF.IGM.getSILModule().Types.getConstantFunctionType(declRef);
70+
71+
// Load the metadata, or use the 'self' value if we have a static method.
72+
llvm::Value *self;
73+
74+
// Non-throwing class methods always have the 'self' parameter at the end.
75+
// Throwing class methods have 'self' right before the error parameter.
76+
//
77+
// FIXME: Should find a better way of expressing this.
78+
if (funcTy->hasErrorResult())
79+
self = (IGF.CurFn->arg_end() - 2);
80+
else
81+
self = (IGF.CurFn->arg_end() - 1);
82+
83+
auto selfTy = funcTy->getSelfParameter().getSILStorageType();
84+
85+
llvm::Value *metadata;
86+
if (selfTy.is<MetatypeType>()) {
87+
metadata = self;
88+
} else {
89+
metadata = emitHeapMetadataRefForHeapObject(IGF, self, selfTy,
90+
/*suppress cast*/ true);
91+
}
92+
93+
return emitVirtualMethodValue(IGF, metadata, declRef, funcTy);
6094
}
6195

6296
llvm::Function *IRGenModule::emitDispatchThunk(SILDeclRef declRef) {

lib/IRGen/IRGenSIL.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5378,6 +5378,19 @@ void IRGenSILFunction::visitClassMethodInst(swift::ClassMethodInst *i) {
53785378
SILDeclRef method = i->getMember();
53795379
auto methodType = i->getType().castTo<SILFunctionType>();
53805380

5381+
auto *classDecl = cast<ClassDecl>(method.getDecl()->getDeclContext());
5382+
5383+
if (IGM.isResilient(classDecl,
5384+
ResilienceExpansion::Maximal)) {
5385+
method = method.getOverriddenVTableEntry();
5386+
auto *fnPtr = IGM.getAddrOfDispatchThunk(method, NotForDefinition);
5387+
auto sig = IGM.getSignature(methodType);
5388+
FunctionPointer fn(fnPtr, sig);
5389+
5390+
setLoweredFunctionPointer(i, fn);
5391+
return;
5392+
}
5393+
53815394
// For Swift classes, get the method implementation from the vtable.
53825395
// FIXME: better explosion kind, map as static.
53835396
FunctionPointer fn = emitVirtualMethodValue(*this, baseValue,

lib/SIL/SILDeclRef.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -583,10 +583,6 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
583583
case SILDeclRef::ManglingKind::DynamicThunk:
584584
SKind = ASTMangler::SymbolKind::DynamicThunk;
585585
break;
586-
case SILDeclRef::ManglingKind::SwiftDispatchThunk:
587-
assert(!isForeign && !isDirectReference && !isCurried);
588-
SKind = ASTMangler::SymbolKind::SwiftDispatchThunk;
589-
break;
590586
}
591587

592588
switch (kind) {

lib/SILGen/SILGen.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
149149
SILFunction *getFunction(SILDeclRef constant,
150150
ForDefinition_t forDefinition);
151151

152-
/// Get the function for a dispatch thunk, creating it if necessary.
153-
SILFunction *getDispatchThunk(SILDeclRef constant,
154-
ForDefinition_t forDefinition);
155-
156-
/// Emit a native Swift class or protocol method dispatch thunk, used for
157-
/// resilient method dispatch.
158-
SILFunction *emitDispatchThunk(SILDeclRef constant);
159-
160152
/// Get the dynamic dispatch thunk for a SILDeclRef.
161153
SILFunction *getDynamicThunk(SILDeclRef constant,
162154
CanSILFunctionType constantTy);

lib/SILGen/SILGenFunction.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,8 +521,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
521521
void emitForeignToNativeThunk(SILDeclRef thunk);
522522
/// Generates a thunk from a native function to the conventions.
523523
void emitNativeToForeignThunk(SILDeclRef thunk);
524-
/// Generates a resilient method dispatch thunk.
525-
void emitDispatchThunk(SILDeclRef constant);
526524

527525
/// Generate a nullary function that returns the given value.
528526
void emitGeneratorFunction(SILDeclRef function, Expr *value);

lib/SILGen/SILGenThunk.cpp

Lines changed: 0 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -33,107 +33,11 @@
3333
using namespace swift;
3434
using namespace Lowering;
3535

36-
SILFunction *SILGenModule::getDispatchThunk(SILDeclRef constant,
37-
ForDefinition_t forDefinition) {
38-
// Mangle the constant with a Tv suffix.
39-
auto name = constant.mangle(SILDeclRef::ManglingKind::SwiftDispatchThunk);
40-
auto constantTy = M.Types.getConstantOverrideType(constant);
41-
42-
auto linkage = (forDefinition
43-
? SILLinkage::Public
44-
: SILLinkage::PublicExternal);
45-
46-
// N.B.: Right now, we don't serialize vtables in resilient modules,
47-
// so there's nothing to gain from marking these as serialized.
48-
return M.getOrCreateFunction(constant.getDecl(), name, linkage,
49-
constantTy, IsBare, IsNotTransparent,
50-
IsNotSerialized, ProfileCounter(), IsThunk);
51-
}
52-
53-
SILFunction *SILGenModule::emitDispatchThunk(SILDeclRef constant) {
54-
auto *F = getDispatchThunk(constant, ForDefinition);
55-
56-
if (F->empty()) {
57-
auto *afd = cast<AbstractFunctionDecl>(constant.getDecl());
58-
59-
preEmitFunction(constant, afd, F, afd);
60-
SILGenFunction SGF(*this, *F);
61-
SGF.emitDispatchThunk(constant);
62-
postEmitFunction(constant, F);
63-
}
64-
65-
return F;
66-
}
67-
68-
void SILGenFunction::emitDispatchThunk(SILDeclRef constant) {
69-
auto *afd = cast<AbstractFunctionDecl>(constant.getDecl());
70-
71-
SILLocation loc(afd);
72-
loc.markAutoGenerated();
73-
74-
auto subs = F.getForwardingSubstitutions();
75-
76-
SmallVector<SILValue, 8> args;
77-
78-
// Add the indirect results.
79-
for (auto resultTy : F.getConventions().getIndirectSILResultTypes()) {
80-
auto paramTy = F.mapTypeIntoContext(resultTy);
81-
args.push_back(F.begin()->createFunctionArgument(paramTy));
82-
}
83-
84-
// Add the parameters.
85-
auto paramTypes = F.getLoweredFunctionType()->getParameters();
86-
for (auto param : paramTypes) {
87-
auto paramTy = F.mapTypeIntoContext(F.getConventions().getSILType(param));
88-
args.push_back(F.begin()->createFunctionArgument(paramTy));
89-
}
90-
91-
auto constantTy = F.getLoweredFunctionType();
92-
93-
auto selfPtr = args.back();
94-
auto fnValue =
95-
B.createClassMethod(loc, selfPtr, constant,
96-
SILType::getPrimitiveObjectType(constantTy));
97-
auto substFnType = fnValue->getType().substGenericArgs(SGM.M, subs);
98-
auto result =
99-
emitApplyWithRethrow(loc, fnValue, substFnType, subs, args);
100-
101-
B.createReturn(loc, result);
102-
}
103-
104-
static bool shouldUseDispatchThunk(SILDeclRef constant,
105-
SILFunction *F,
106-
SILModule &M) {
107-
auto *afd = cast<AbstractFunctionDecl>(constant.getDecl());
108-
auto *classDecl = cast<ClassDecl>(afd->getDeclContext());
109-
110-
// Resilient classes in other resilience domains use dispatch thunks.
111-
return classDecl->isResilient(M.getSwiftModule(),
112-
F->getResilienceExpansion());
113-
}
114-
11536
SILValue SILGenFunction::emitClassMethodRef(SILLocation loc,
11637
SILValue selfPtr,
11738
SILDeclRef constant,
11839
CanSILFunctionType constantTy) {
11940
assert(!constant.isForeign);
120-
121-
// Not every override gets a dispatch thunk; find the least derived one
122-
// that does.
123-
auto base = constant.getOverriddenVTableEntry();
124-
125-
if (shouldUseDispatchThunk(base, &F, SGM.M)) {
126-
auto *thunkFn = SGM.getDispatchThunk(base, NotForDefinition);
127-
128-
SILValue ref = B.createFunctionRef(loc, thunkFn);
129-
if (thunkFn->getLoweredFunctionType() != constantTy) {
130-
auto resultTy = SILType::getPrimitiveObjectType(constantTy);
131-
ref = B.createConvertFunction(loc, ref, resultTy);
132-
}
133-
134-
return ref;
135-
}
136-
13741
return B.createClassMethod(loc, selfPtr, constant,
13842
SILType::getPrimitiveObjectType(constantTy));
13943
}

lib/SILGen/SILGenType.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -265,16 +265,6 @@ class SILGenVTable : public SILVTableVisitor<SILGenVTable> {
265265
auto result = baseToIndexMap.insert(std::make_pair(member, index));
266266
assert(result.second);
267267
(void) result;
268-
269-
// Emit a method dispatch thunk if the method is public and the
270-
// class is resilient.
271-
auto *func = cast<AbstractFunctionDecl>(member.getDecl());
272-
if (func->getDeclContext() == theClass) {
273-
if (isResilient &&
274-
func->getEffectiveAccess() >= AccessLevel::Public) {
275-
SGM.emitDispatchThunk(member);
276-
}
277-
}
278268
}
279269

280270
void addPlaceholder(MissingMemberDecl *m) {

0 commit comments

Comments
 (0)