Skip to content

Commit 9efe1c2

Browse files
authored
Merge pull request #13742 from slavapestov/method-dispatch-cleanup
Method dispatch cleanup
2 parents 0429813 + a278bd2 commit 9efe1c2

File tree

12 files changed

+129
-346
lines changed

12 files changed

+129
-346
lines changed

include/swift/AST/Decl.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4248,14 +4248,6 @@ class AbstractStorageDecl : public ValueDecl {
42484248
/// only valid on a declaration with Observing storage.
42494249
FuncDecl *getDidSetFunc() const { return getDidSetInfo().DidSet; }
42504250

4251-
/// Return true if this storage can (but doesn't have to) be accessed with
4252-
/// Objective-C-compatible getters and setters.
4253-
bool hasForeignGetterAndSetter() const;
4254-
4255-
/// Return true if this storage *must* be accessed with Objective-C-compatible
4256-
/// getters and setters.
4257-
bool requiresForeignGetterAndSetter() const;
4258-
42594251
/// Given that this is an Objective-C property or subscript declaration,
42604252
/// produce its getter selector.
42614253
ObjCSelector getObjCGetterSelector(LazyResolver *resolver = nullptr,

lib/AST/Decl.cpp

Lines changed: 14 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,34 +1260,25 @@ SourceRange IfConfigDecl::getSourceRange() const {
12601260
}
12611261

12621262
static bool isPolymorphic(const AbstractStorageDecl *storage) {
1263-
auto nominal = storage->getDeclContext()
1264-
->getAsNominalTypeOrNominalTypeExtensionContext();
1265-
if (!nominal) return false;
1266-
1267-
switch (nominal->getKind()) {
1268-
#define DECL(ID, BASE) case DeclKind::ID:
1269-
#define NOMINAL_TYPE_DECL(ID, BASE)
1270-
#include "swift/AST/DeclNodes.def"
1271-
llvm_unreachable("not a nominal type!");
1272-
1273-
case DeclKind::Struct:
1274-
case DeclKind::Enum:
1275-
return false;
1263+
if (storage->isDynamic())
1264+
return true;
12761265

1277-
case DeclKind::Protocol:
1278-
return !storage->getDeclContext()->isExtensionContext();
1266+
// Imported declarations behave like they are dynamic, even if they're
1267+
// not marked as such explicitly.
1268+
if (storage->isObjC() && storage->hasClangNode())
1269+
return true;
12791270

1280-
case DeclKind::Class:
1281-
// Final properties can always be direct, even in classes.
1282-
if (storage->isFinal())
1283-
return false;
1284-
// Extension properties are statically dispatched, unless they're @objc.
1285-
if (storage->getDeclContext()->isExtensionContext()
1286-
&& !storage->isObjC())
1271+
if (auto *classDecl = dyn_cast<ClassDecl>(storage->getDeclContext())) {
1272+
if (storage->isFinal() || classDecl->isFinal())
12871273
return false;
1274+
12881275
return true;
12891276
}
1290-
llvm_unreachable("bad DeclKind");
1277+
1278+
if (auto *protoDecl = dyn_cast<ProtocolDecl>(storage->getDeclContext()))
1279+
return true;
1280+
1281+
return false;
12911282
}
12921283

12931284
/// Determines the access semantics to use in a DeclRefExpr or
@@ -4186,36 +4177,6 @@ bool VarDecl::isSelfParameter() const {
41864177
return false;
41874178
}
41884179

4189-
/// Return true if this stored property has a getter and
4190-
/// setter that are accessible from Objective-C.
4191-
bool AbstractStorageDecl::hasForeignGetterAndSetter() const {
4192-
if (auto override = getOverriddenDecl())
4193-
return override->hasForeignGetterAndSetter();
4194-
4195-
if (!isObjC())
4196-
return false;
4197-
4198-
return true;
4199-
}
4200-
4201-
bool AbstractStorageDecl::requiresForeignGetterAndSetter() const {
4202-
if (isFinal())
4203-
return false;
4204-
if (hasAccessorFunctions() && getGetter()->isImportAsMember())
4205-
return true;
4206-
if (!hasForeignGetterAndSetter())
4207-
return false;
4208-
// Imported accessors are foreign and only have objc entry points.
4209-
if (hasClangNode())
4210-
return true;
4211-
// Otherwise, we only dispatch by @objc if the declaration is dynamic,
4212-
// NSManaged, or dispatched through an ObjC protocol.
4213-
return isDynamic()
4214-
|| getAttrs().hasAttribute<NSManagedAttr>()
4215-
|| (isa<ProtocolDecl>(getDeclContext()) && isProtocolRequirement());
4216-
}
4217-
4218-
42194180
bool VarDecl::isAnonClosureParam() const {
42204181
auto name = getName();
42214182
if (name.empty())

lib/SIL/SILDeclRef.cpp

Lines changed: 25 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ using namespace swift;
3030
/// Get the method dispatch mechanism for a method.
3131
MethodDispatch
3232
swift::getMethodDispatch(AbstractFunctionDecl *method) {
33-
// Final methods can be statically referenced.
34-
if (method->isFinal())
35-
return MethodDispatch::Static;
3633
// Some methods are forced to be statically dispatched.
3734
if (method->hasForcedStaticDispatch())
3835
return MethodDispatch::Static;
@@ -41,23 +38,23 @@ swift::getMethodDispatch(AbstractFunctionDecl *method) {
4138
if (method->isImportAsMember())
4239
return MethodDispatch::Static;
4340

44-
// If this declaration is in a class but not marked final, then it is
45-
// always dynamically dispatched.
4641
auto dc = method->getDeclContext();
47-
if (isa<ClassDecl>(dc))
48-
return MethodDispatch::Class;
4942

50-
// Class extension methods are only dynamically dispatched if they're
51-
// dispatched by objc_msgSend, which happens if they're foreign or dynamic.
5243
if (dc->getAsClassOrClassExtensionContext()) {
53-
if (method->hasClangNode())
54-
return MethodDispatch::Class;
55-
if (auto fd = dyn_cast<FuncDecl>(method)) {
56-
if (fd->isAccessor() && fd->getAccessorStorageDecl()->hasClangNode())
57-
return MethodDispatch::Class;
58-
}
5944
if (method->isDynamic())
6045
return MethodDispatch::Class;
46+
47+
// Final methods can be statically referenced.
48+
if (method->isFinal())
49+
return MethodDispatch::Static;
50+
51+
// Members defined directly inside a class are dynamically dispatched.
52+
if (isa<ClassDecl>(dc))
53+
return MethodDispatch::Class;
54+
55+
// Imported class methods are dynamically dispatched.
56+
if (method->isObjC() && method->hasClangNode())
57+
return MethodDispatch::Class;
6158
}
6259

6360
// Otherwise, it can be referenced statically.
@@ -79,151 +76,30 @@ bool swift::requiresForeignToNativeThunk(ValueDecl *vd) {
7976
return false;
8077
}
8178

82-
/// FIXME: merge requiresForeignEntryPoint() into getMethodDispatch() and add
83-
/// an ObjectiveC case to the MethodDispatch enum.
8479
bool swift::requiresForeignEntryPoint(ValueDecl *vd) {
85-
if (vd->isImportAsMember())
80+
assert(!isa<AbstractStorageDecl>(vd));
81+
82+
if (vd->isDynamic())
8683
return true;
8784

88-
// Final functions never require ObjC dispatch.
89-
if (vd->isFinal())
90-
return false;
85+
if (vd->isObjC() && isa<ProtocolDecl>(vd->getDeclContext()))
86+
return true;
87+
88+
if (vd->isImportAsMember())
89+
return true;
9190

92-
if (requiresForeignToNativeThunk(vd))
91+
if (vd->hasClangNode())
9392
return true;
9493

9594
if (auto *fd = dyn_cast<FuncDecl>(vd)) {
96-
9795
// Property accessors should be generated alongside the property.
98-
if (fd->isGetterOrSetter())
99-
return requiresForeignEntryPoint(fd->getAccessorStorageDecl());
100-
101-
return fd->isDynamic();
102-
}
103-
104-
if (auto *cd = dyn_cast<ConstructorDecl>(vd)) {
105-
if (cd->hasClangNode())
106-
return true;
107-
108-
return cd->isDynamic();
109-
}
110-
111-
if (auto *asd = dyn_cast<AbstractStorageDecl>(vd))
112-
return asd->requiresForeignGetterAndSetter();
113-
114-
return vd->isDynamic();
115-
}
116-
117-
/// TODO: We should consult the cached LoweredLocalCaptures the SIL
118-
/// TypeConverter calculates, but that would require plumbing SILModule&
119-
/// through every SILDeclRef constructor. Since this is only used to determine
120-
/// "natural uncurry level", and "uncurry level" is a concept we'd like to
121-
/// phase out, it's not worth it.
122-
static bool hasLoweredLocalCaptures(AnyFunctionRef AFR,
123-
llvm::DenseSet<AnyFunctionRef> &visited) {
124-
if (!AFR.getCaptureInfo().hasLocalCaptures())
125-
return false;
126-
127-
// Scan for local, non-function captures.
128-
bool functionCapturesToRecursivelyCheck = false;
129-
auto addFunctionCapture = [&](AnyFunctionRef capture) {
130-
if (visited.find(capture) == visited.end())
131-
functionCapturesToRecursivelyCheck = true;
132-
};
133-
for (auto &capture : AFR.getCaptureInfo().getCaptures()) {
134-
if (!capture.getDecl()->getDeclContext()->isLocalContext())
135-
continue;
136-
// We transitively capture a local function's captures.
137-
if (auto func = dyn_cast<AbstractFunctionDecl>(capture.getDecl())) {
138-
addFunctionCapture(func);
139-
continue;
140-
}
141-
// We may either directly capture properties, or capture through their
142-
// accessors.
143-
if (auto var = dyn_cast<VarDecl>(capture.getDecl())) {
144-
switch (var->getStorageKind()) {
145-
case VarDecl::StoredWithTrivialAccessors:
146-
llvm_unreachable("stored local variable with trivial accessors?");
147-
148-
case VarDecl::InheritedWithObservers:
149-
llvm_unreachable("inherited local variable?");
150-
151-
case VarDecl::StoredWithObservers:
152-
case VarDecl::Addressed:
153-
case VarDecl::AddressedWithTrivialAccessors:
154-
case VarDecl::AddressedWithObservers:
155-
case VarDecl::ComputedWithMutableAddress:
156-
// Directly capture storage if we're supposed to.
157-
if (capture.isDirect())
158-
return true;
159-
160-
// Otherwise, transitively capture the accessors.
161-
LLVM_FALLTHROUGH;
162-
163-
case VarDecl::Computed:
164-
addFunctionCapture(var->getGetter());
165-
if (auto setter = var->getSetter())
166-
addFunctionCapture(setter);
167-
continue;
168-
169-
case VarDecl::Stored:
96+
if (fd->isGetterOrSetter()) {
97+
auto *asd = fd->getAccessorStorageDecl();
98+
if (asd->isObjC() && asd->hasClangNode())
17099
return true;
171-
}
172100
}
173-
// Anything else is directly captured.
174-
return true;
175101
}
176-
177-
// Recursively consider function captures, since we didn't have any direct
178-
// captures.
179-
auto captureHasLocalCaptures = [&](AnyFunctionRef capture) -> bool {
180-
if (visited.insert(capture).second)
181-
return hasLoweredLocalCaptures(capture, visited);
182-
return false;
183-
};
184-
185-
if (functionCapturesToRecursivelyCheck) {
186-
for (auto &capture : AFR.getCaptureInfo().getCaptures()) {
187-
if (!capture.getDecl()->getDeclContext()->isLocalContext())
188-
continue;
189-
if (auto func = dyn_cast<AbstractFunctionDecl>(capture.getDecl())) {
190-
if (captureHasLocalCaptures(func))
191-
return true;
192-
continue;
193-
}
194-
if (auto var = dyn_cast<VarDecl>(capture.getDecl())) {
195-
switch (var->getStorageKind()) {
196-
case VarDecl::StoredWithTrivialAccessors:
197-
llvm_unreachable("stored local variable with trivial accessors?");
198-
199-
case VarDecl::InheritedWithObservers:
200-
llvm_unreachable("inherited local variable?");
201-
202-
case VarDecl::StoredWithObservers:
203-
case VarDecl::Addressed:
204-
case VarDecl::AddressedWithTrivialAccessors:
205-
case VarDecl::AddressedWithObservers:
206-
case VarDecl::ComputedWithMutableAddress:
207-
assert(!capture.isDirect() && "should have short circuited out");
208-
// Otherwise, transitively capture the accessors.
209-
LLVM_FALLTHROUGH;
210-
211-
case VarDecl::Computed:
212-
if (captureHasLocalCaptures(var->getGetter()))
213-
return true;
214-
if (auto setter = var->getSetter())
215-
if (captureHasLocalCaptures(setter))
216-
return true;
217-
continue;
218-
219-
case VarDecl::Stored:
220-
llvm_unreachable("should have short circuited out");
221-
}
222-
}
223-
llvm_unreachable("should have short circuited out");
224-
}
225-
}
226-
102+
227103
return false;
228104
}
229105

lib/SILGen/SILGenApply.cpp

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4736,7 +4736,7 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &SGF,
47364736
}
47374737

47384738
// Dispatch in a struct/enum or to a final method is always direct.
4739-
if (!isClassDispatch || decl->isFinal())
4739+
if (!isClassDispatch)
47404740
return Callee::forDirect(SGF, constant, subs, loc);
47414741

47424742
// Otherwise, if we have a non-final class dispatch to a normal method,
@@ -4974,28 +4974,10 @@ ArgumentSource SILGenFunction::prepareAccessorBaseArg(SILLocation loc,
49744974
return Preparer.prepare();
49754975
}
49764976

4977-
static bool shouldReferenceForeignAccessor(AbstractStorageDecl *storage,
4978-
bool isDirectUse) {
4979-
// Members of Objective-C protocols should be dynamically dispatched.
4980-
if (auto *protoDecl = dyn_cast<ProtocolDecl>(storage->getDeclContext()))
4981-
return protoDecl->isObjC();
4982-
4983-
// C functions imported as members should be referenced as C functions.
4984-
if (storage->getGetter()->isImportAsMember())
4985-
return true;
4986-
4987-
// Otherwise, favor native entry points for direct accesses.
4988-
if (isDirectUse)
4989-
return false;
4990-
4991-
return storage->requiresForeignGetterAndSetter();
4992-
}
4993-
4994-
SILDeclRef SILGenFunction::getGetterDeclRef(AbstractStorageDecl *storage,
4995-
bool isDirectUse) {
4996-
// Use the ObjC entry point
4997-
return SILDeclRef(storage->getGetter(), SILDeclRef::Kind::Func)
4998-
.asForeign(shouldReferenceForeignAccessor(storage, isDirectUse));
4977+
SILDeclRef SILGenFunction::getGetterDeclRef(AbstractStorageDecl *storage) {
4978+
auto *getter = storage->getGetter();
4979+
return SILDeclRef(getter, SILDeclRef::Kind::Func)
4980+
.asForeign(requiresForeignEntryPoint(getter));
49994981
}
50004982

50014983
/// Emit a call to a getter.
@@ -5031,10 +5013,10 @@ emitGetAccessor(SILLocation loc, SILDeclRef get,
50315013
return emission.apply(c);
50325014
}
50335015

5034-
SILDeclRef SILGenFunction::getSetterDeclRef(AbstractStorageDecl *storage,
5035-
bool isDirectUse) {
5036-
return SILDeclRef(storage->getSetter(), SILDeclRef::Kind::Func)
5037-
.asForeign(shouldReferenceForeignAccessor(storage, isDirectUse));
5016+
SILDeclRef SILGenFunction::getSetterDeclRef(AbstractStorageDecl *storage) {
5017+
auto *setter = storage->getSetter();
5018+
return SILDeclRef(setter, SILDeclRef::Kind::Func)
5019+
.asForeign(requiresForeignEntryPoint(setter));
50385020
}
50395021

50405022
void SILGenFunction::emitSetAccessor(SILLocation loc, SILDeclRef set,
@@ -5097,8 +5079,7 @@ void SILGenFunction::emitSetAccessor(SILLocation loc, SILDeclRef set,
50975079
}
50985080

50995081
SILDeclRef
5100-
SILGenFunction::getMaterializeForSetDeclRef(AbstractStorageDecl *storage,
5101-
bool isDirectUse) {
5082+
SILGenFunction::getMaterializeForSetDeclRef(AbstractStorageDecl *storage) {
51025083
return SILDeclRef(storage->getMaterializeForSetFunc(),
51035084
SILDeclRef::Kind::Func);
51045085
}
@@ -5176,8 +5157,7 @@ emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
51765157
}
51775158

51785159
SILDeclRef SILGenFunction::getAddressorDeclRef(AbstractStorageDecl *storage,
5179-
AccessKind accessKind,
5180-
bool isDirectUse) {
5160+
AccessKind accessKind) {
51815161
FuncDecl *addressorFunc = storage->getAddressorForAccess(accessKind);
51825162
return SILDeclRef(addressorFunc, SILDeclRef::Kind::Func);
51835163
}

0 commit comments

Comments
 (0)