Skip to content

Commit 832a637

Browse files
committed
SIL: Start cleaning up getMethodDispatch() / requiresObjCDispatch()
Move these to SILDeclRef, maybe not the best place but a good home for now. Factor out a new requiresForeignToNativeThunk() function, which cleans up some code duplication introduced by the following patch: 478e1c7 This is a small step towards consolidating duplicated logic for figuring out method dispatch semantics and emitting curry thunks.
1 parent c31b209 commit 832a637

File tree

7 files changed

+110
-119
lines changed

7 files changed

+110
-119
lines changed

include/swift/SIL/SILDeclRef.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,23 @@ namespace swift {
4545
class SILLocation;
4646
class AnyFunctionRef;
4747

48+
/// How a method is dispatched.
49+
enum class MethodDispatch {
50+
// The method implementation can be referenced statically.
51+
Static,
52+
// The method implementation uses class_method dispatch.
53+
Class,
54+
};
55+
56+
/// Get the method dispatch mechanism for a method.
57+
MethodDispatch getMethodDispatch(AbstractFunctionDecl *method);
58+
59+
/// True if calling the given method or property should use ObjC dispatch.
60+
bool requiresObjCDispatch(ValueDecl *vd);
61+
62+
/// True if the entry point is natively foreign.
63+
bool requiresForeignToNativeThunk(ValueDecl *vd);
64+
4865
enum ForDefinition_t : bool {
4966
NotForDefinition = false,
5067
ForDefinition = true

lib/SIL/SILDeclRef.cpp

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,85 @@
2525
#include "clang/AST/DeclObjC.h"
2626
using namespace swift;
2727

28+
/// Get the method dispatch mechanism for a method.
29+
MethodDispatch
30+
swift::getMethodDispatch(AbstractFunctionDecl *method) {
31+
// Final methods can be statically referenced.
32+
if (method->isFinal())
33+
return MethodDispatch::Static;
34+
// Some methods are forced to be statically dispatched.
35+
if (method->hasForcedStaticDispatch())
36+
return MethodDispatch::Static;
37+
38+
// If this declaration is in a class but not marked final, then it is
39+
// always dynamically dispatched.
40+
auto dc = method->getDeclContext();
41+
if (isa<ClassDecl>(dc))
42+
return MethodDispatch::Class;
43+
44+
// Class extension methods are only dynamically dispatched if they're
45+
// dispatched by objc_msgSend, which happens if they're foreign or dynamic.
46+
if (dc->isClassOrClassExtensionContext()) {
47+
if (method->hasClangNode())
48+
return MethodDispatch::Class;
49+
if (auto fd = dyn_cast<FuncDecl>(method)) {
50+
if (fd->isAccessor() && fd->getAccessorStorageDecl()->hasClangNode())
51+
return MethodDispatch::Class;
52+
}
53+
if (method->getAttrs().hasAttribute<DynamicAttr>())
54+
return MethodDispatch::Class;
55+
}
56+
57+
// Otherwise, it can be referenced statically.
58+
return MethodDispatch::Static;
59+
}
60+
61+
bool swift::requiresForeignToNativeThunk(ValueDecl *vd) {
62+
// Functions imported from C, Objective-C methods imported from Objective-C,
63+
// as well as methods in @objc protocols (even protocols defined in Swift)
64+
// require a foreign to native thunk.
65+
auto dc = vd->getDeclContext();
66+
if (auto proto = dyn_cast<ProtocolDecl>(dc))
67+
if (proto->isObjC())
68+
return true;
69+
70+
if (auto fd = dyn_cast<FuncDecl>(vd))
71+
return fd->hasClangNode();
72+
73+
return false;
74+
}
75+
76+
/// FIXME: merge requiresObjCDispatch() into getMethodDispatch() and add
77+
/// an ObjectiveC case to the MethodDispatch enum.
78+
bool swift::requiresObjCDispatch(ValueDecl *vd) {
79+
// Final functions never require ObjC dispatch.
80+
if (vd->isFinal())
81+
return false;
82+
83+
if (requiresForeignToNativeThunk(vd))
84+
return true;
85+
86+
if (auto *fd = dyn_cast<FuncDecl>(vd)) {
87+
// Property accessors should be generated alongside the property.
88+
if (fd->isGetterOrSetter())
89+
return requiresObjCDispatch(fd->getAccessorStorageDecl());
90+
91+
return fd->getAttrs().hasAttribute<DynamicAttr>();
92+
}
93+
94+
if (auto *cd = dyn_cast<ConstructorDecl>(vd)) {
95+
if (cd->hasClangNode())
96+
return true;
97+
98+
return cd->getAttrs().hasAttribute<DynamicAttr>();
99+
}
100+
101+
if (auto *asd = dyn_cast<AbstractStorageDecl>(vd))
102+
return asd->requiresObjCGetterAndSetter();
103+
104+
return vd->getAttrs().hasAttribute<DynamicAttr>();
105+
}
106+
28107
static unsigned getFuncNaturalUncurryLevel(AnyFunctionRef AFR) {
29108
assert(AFR.getBodyParamPatterns().size() >= 1 && "no arguments for func?!");
30109
unsigned Level = AFR.getBodyParamPatterns().size() - 1;
@@ -338,14 +417,8 @@ bool SILDeclRef::isForeignToNativeThunk() const {
338417
// have a foreign-to-native thunk.
339418
if (!hasDecl())
340419
return false;
341-
// Otherwise, match whether we have a clang node with whether we're foreign.
342-
if (isa<FuncDecl>(getDecl()) && getDecl()->hasClangNode())
420+
if (requiresForeignToNativeThunk(getDecl()))
343421
return !isForeign;
344-
// Objective-C protocol methods also require a foreign to native thunk.
345-
auto dc = getDecl()->getDeclContext();
346-
if (auto proto = dyn_cast<ProtocolDecl>(dc))
347-
if (proto->isObjC())
348-
return !isForeign;
349422
// ObjC initializing constructors and factories are foreign.
350423
// We emit a special native allocating constructor though.
351424
if (isa<ConstructorDecl>(getDecl())

lib/SILGen/SILGen.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -323,13 +323,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
323323
/// True if the given constructor requires an entry point for ObjC method
324324
/// dispatch.
325325
bool requiresObjCMethodEntryPoint(ConstructorDecl *constructor);
326-
327-
/// True if calling the given method or property should use ObjC dispatch.
328-
bool requiresObjCDispatch(ValueDecl *vd);
329-
330-
/// True if super-calling the given method from a subclass should use ObjC
331-
/// dispatch.
332-
bool requiresObjCSuperDispatch(ValueDecl *vd);
333326

334327
/// Emit a global initialization.
335328
void emitGlobalInitialization(PatternBindingDecl *initializer, unsigned elt);

lib/SILGen/SILGenApply.cpp

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -29,40 +29,6 @@
2929
using namespace swift;
3030
using namespace Lowering;
3131

32-
/// Get the method dispatch mechanism for a method.
33-
MethodDispatch
34-
SILGenFunction::getMethodDispatch(AbstractFunctionDecl *method) {
35-
// Final methods can be statically referenced.
36-
if (method->isFinal())
37-
return MethodDispatch::Static;
38-
// Some methods are forced to be statically dispatched.
39-
if (method->hasForcedStaticDispatch())
40-
return MethodDispatch::Static;
41-
42-
// If this declaration is in a class but not marked final, then it is
43-
// always dynamically dispatched.
44-
auto dc = method->getDeclContext();
45-
if (isa<ClassDecl>(dc))
46-
return MethodDispatch::Class;
47-
48-
// Class extension methods are only dynamically dispatched if they're
49-
// dispatched by objc_msgSend, which happens if they're foreign or dynamic.
50-
if (auto declaredType = dc->getDeclaredTypeInContext())
51-
if (declaredType->getClassOrBoundGenericClass()) {
52-
if (method->hasClangNode())
53-
return MethodDispatch::Class;
54-
if (auto fd = dyn_cast<FuncDecl>(method)) {
55-
if (fd->isAccessor() && fd->getAccessorStorageDecl()->hasClangNode())
56-
return MethodDispatch::Class;
57-
}
58-
if (method->getAttrs().hasAttribute<DynamicAttr>())
59-
return MethodDispatch::Class;
60-
}
61-
62-
// Otherwise, it can be referenced statically.
63-
return MethodDispatch::Static;
64-
}
65-
6632
static SILDeclRef::Loc getLocForFunctionRef(AnyFunctionRef fn) {
6733
if (auto afd = fn.getAbstractFunctionDecl()) {
6834
return afd;
@@ -539,7 +505,7 @@ class Callee {
539505
// make sure we emit the right set of thunks.
540506
if (constant->isCurried && Constant.hasDecl())
541507
if (auto func = Constant.getAbstractFunctionDecl())
542-
if (gen.getMethodDispatch(func) == MethodDispatch::Class)
508+
if (getMethodDispatch(func) == MethodDispatch::Class)
543509
constant = constant->asDirectReference(true);
544510

545511
constantInfo = gen.getConstantInfo(*constant);
@@ -1102,7 +1068,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11021068
if (e->getAccessSemantics() != AccessSemantics::Ordinary) {
11031069
isDynamicallyDispatched = false;
11041070
} else {
1105-
switch (SGF.getMethodDispatch(afd)) {
1071+
switch (getMethodDispatch(afd)) {
11061072
case MethodDispatch::Class:
11071073
isDynamicallyDispatched = true;
11081074
break;
@@ -1121,7 +1087,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11211087
if (ctor->isRequired() &&
11221088
thisCallSite->getArg()->getType()->is<AnyMetatypeType>() &&
11231089
!thisCallSite->getArg()->isStaticallyDerivedMetatype()) {
1124-
if (SGF.SGM.requiresObjCDispatch(afd)) {
1090+
if (requiresObjCDispatch(afd)) {
11251091
// When we're performing Objective-C dispatch, we don't have an
11261092
// allocating constructor to call. So, perform an alloc_ref_dynamic
11271093
// and pass that along to the initializer.
@@ -1171,7 +1137,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11711137
SILDeclRef constant(afd, kind.getValue(),
11721138
SILDeclRef::ConstructAtBestResilienceExpansion,
11731139
SILDeclRef::ConstructAtNaturalUncurryLevel,
1174-
SGF.SGM.requiresObjCDispatch(afd));
1140+
requiresObjCDispatch(afd));
11751141

11761142
setCallee(Callee::forClassMethod(SGF, selfValue,
11771143
constant, getSubstFnType(), e));
@@ -1203,7 +1169,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
12031169
SILDeclRef constant(e->getDecl(),
12041170
SILDeclRef::ConstructAtBestResilienceExpansion,
12051171
SILDeclRef::ConstructAtNaturalUncurryLevel,
1206-
SGF.SGM.requiresObjCDispatch(e->getDecl()));
1172+
requiresObjCDispatch(e->getDecl()));
12071173

12081174
// Otherwise, we have a statically-dispatched call.
12091175
CanFunctionType substFnType = getSubstFnType();
@@ -1345,7 +1311,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
13451311
constant = SILDeclRef(ctorRef->getDecl(), SILDeclRef::Kind::Initializer,
13461312
SILDeclRef::ConstructAtBestResilienceExpansion,
13471313
SILDeclRef::ConstructAtNaturalUncurryLevel,
1348-
SGF.SGM.requiresObjCSuperDispatch(ctorRef->getDecl()));
1314+
requiresObjCDispatch(ctorRef->getDecl()));
13491315

13501316
if (ctorRef->getDeclRef().isSpecialized())
13511317
substitutions = ctorRef->getDeclRef().getSubstitutions();
@@ -1354,7 +1320,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
13541320
constant = SILDeclRef(declRef->getDecl(),
13551321
SILDeclRef::ConstructAtBestResilienceExpansion,
13561322
SILDeclRef::ConstructAtNaturalUncurryLevel,
1357-
SGF.SGM.requiresObjCSuperDispatch(declRef->getDecl()));
1323+
requiresObjCDispatch(declRef->getDecl()));
13581324

13591325
if (declRef->getDeclRef().isSpecialized())
13601326
substitutions = declRef->getDeclRef().getSubstitutions();
@@ -1536,12 +1502,12 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
15361502
: SILDeclRef::Kind::Initializer,
15371503
SILDeclRef::ConstructAtBestResilienceExpansion,
15381504
SILDeclRef::ConstructAtNaturalUncurryLevel,
1539-
SGF.SGM.requiresObjCDispatch(ctorRef->getDecl()));
1505+
requiresObjCDispatch(ctorRef->getDecl()));
15401506
setCallee(Callee::forArchetype(SGF, SILValue(),
15411507
self.getType().getSwiftRValueType(), constant,
15421508
cast<AnyFunctionType>(expr->getType()->getCanonicalType()),
15431509
expr));
1544-
} else if (SGF.getMethodDispatch(ctorRef->getDecl())
1510+
} else if (getMethodDispatch(ctorRef->getDecl())
15451511
== MethodDispatch::Class) {
15461512
// Dynamic dispatch to the initializer.
15471513
setCallee(Callee::forClassMethod(
@@ -1553,7 +1519,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
15531519
: SILDeclRef::Kind::Initializer,
15541520
SILDeclRef::ConstructAtBestResilienceExpansion,
15551521
SILDeclRef::ConstructAtNaturalUncurryLevel,
1556-
SGF.SGM.requiresObjCDispatch(ctorRef->getDecl())),
1522+
requiresObjCDispatch(ctorRef->getDecl())),
15571523
getSubstFnType(), fn));
15581524
} else {
15591525
// Directly call the peer constructor.
@@ -3799,7 +3765,7 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &gen,
37993765

38003766
bool isClassDispatch = false;
38013767
if (!isDirectUse) {
3802-
switch (gen.getMethodDispatch(decl)) {
3768+
switch (getMethodDispatch(decl)) {
38033769
case MethodDispatch::Class:
38043770
isClassDispatch = true;
38053771
break;

lib/SILGen/SILGenFunction.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,8 @@ SILValue SILGenFunction::emitGlobalFunctionRef(SILLocation loc,
147147
// If the function is fully uncurried and natively foreign, reference its
148148
// foreign entry point.
149149
if (!next.isCurried) {
150-
if (vd->hasClangNode())
150+
if (requiresForeignToNativeThunk(vd))
151151
next = next.asForeign();
152-
153-
// Objective-C protocol methods also require a foreign to native thunk.
154-
auto dc = vd->getDeclContext();
155-
if (auto proto = dyn_cast<ProtocolDecl>(dc))
156-
if (proto->isObjC())
157-
next = next.asForeign();
158152
}
159153

160154
// Preserve whether the curry thunks lead to a direct reference to the
@@ -620,7 +614,7 @@ static SILValue getNextUncurryLevelRef(SILGenFunction &gen,
620614
thisArg = curriedArgs.back();
621615

622616
if (isa<AbstractFunctionDecl>(next.getDecl()) &&
623-
gen.getMethodDispatch(cast<AbstractFunctionDecl>(next.getDecl()))
617+
getMethodDispatch(cast<AbstractFunctionDecl>(next.getDecl()))
624618
== MethodDispatch::Class) {
625619
SILValue thisArg = curriedArgs.back();
626620

lib/SILGen/SILGenFunction.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,6 @@ class LValue;
3131
class ManagedValue;
3232
class RValue;
3333
class TemporaryInitialization;
34-
35-
/// How a method is dispatched.
36-
enum class MethodDispatch {
37-
// The method implementation can be referenced statically.
38-
Static,
39-
// The method implementation uses class_method dispatch.
40-
Class,
41-
};
4234

4335
/// Internal context information for the SILGenFunction visitor.
4436
///
@@ -1540,9 +1532,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
15401532
/// intrinsic.
15411533
Substitution getPointerSubstitution(Type pointerType,
15421534
ArchetypeType *archetype);
1543-
1544-
/// Get the method dispatch mechanism for a method.
1545-
MethodDispatch getMethodDispatch(AbstractFunctionDecl *method);
15461535
};
15471536

15481537

lib/SILGen/SILGenType.cpp

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -136,47 +136,6 @@ bool SILGenModule::requiresObjCMethodEntryPoint(ConstructorDecl *constructor) {
136136
return constructor->isObjC();
137137
}
138138

139-
bool SILGenModule::requiresObjCDispatch(ValueDecl *vd) {
140-
// Final functions never require ObjC dispatch.
141-
if (vd->isFinal())
142-
return false;
143-
144-
// If the decl is an @objc protocol requirement, then the only witness is
145-
// objc.
146-
if (auto *proto = dyn_cast<ProtocolDecl>(vd->getDeclContext()))
147-
if (proto->isObjC())
148-
return true;
149-
150-
if (auto *fd = dyn_cast<FuncDecl>(vd)) {
151-
// If a function has an associated Clang node, it's foreign and only has
152-
// an ObjC entry point.
153-
if (vd->hasClangNode())
154-
return true;
155-
156-
// Property accessors should be generated alongside the property.
157-
if (fd->isGetterOrSetter())
158-
return requiresObjCDispatch(fd->getAccessorStorageDecl());
159-
160-
return fd->getAttrs().hasAttribute<DynamicAttr>();
161-
}
162-
if (auto *cd = dyn_cast<ConstructorDecl>(vd)) {
163-
// If a function has an associated Clang node, it's foreign and only has
164-
// an ObjC entry point.
165-
if (vd->hasClangNode())
166-
return true;
167-
168-
return cd->getAttrs().hasAttribute<DynamicAttr>();
169-
}
170-
if (auto *asd = dyn_cast<AbstractStorageDecl>(vd))
171-
return asd->requiresObjCGetterAndSetter();
172-
173-
return vd->getAttrs().hasAttribute<DynamicAttr>();
174-
}
175-
176-
bool SILGenModule::requiresObjCSuperDispatch(ValueDecl *vd) {
177-
return requiresObjCDispatch(vd);
178-
}
179-
180139
namespace {
181140

182141
/// An ASTVisitor for populating SILVTable entries from ClassDecl members.

0 commit comments

Comments
 (0)