Skip to content

Commit 3aa081c

Browse files
author
Ellis Hoag
committed
[IRGen] Call objc_direct methods correctly
1 parent db594b5 commit 3aa081c

File tree

18 files changed

+388
-37
lines changed

18 files changed

+388
-37
lines changed

lib/AST/NameLookup.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "clang/AST/DeclObjC.h"
1718
#include "swift/AST/NameLookup.h"
1819
#include "swift/AST/ASTContext.h"
1920
#include "swift/AST/ASTVisitor.h"
@@ -1837,6 +1838,17 @@ AnyObjectLookupRequest::evaluate(Evaluator &evaluator, const DeclContext *dc,
18371838
if (!decl->isObjC())
18381839
continue;
18391840

1841+
// If the declaration is objc_direct, it cannot be called dynamically.
1842+
if (auto clangDecl = decl->getClangDecl()) {
1843+
if (auto objCMethod = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
1844+
if (objCMethod->isDirectMethod())
1845+
continue;
1846+
} else if (auto objCProperty = dyn_cast<clang::ObjCPropertyDecl>(clangDecl)) {
1847+
if (objCProperty->isDirectProperty())
1848+
continue;
1849+
}
1850+
}
1851+
18401852
// If the declaration has an override, name lookup will also have
18411853
// found the overridden method. Skip this declaration, because we
18421854
// prefer the overridden method.
@@ -1848,7 +1860,6 @@ AnyObjectLookupRequest::evaluate(Evaluator &evaluator, const DeclContext *dc,
18481860

18491861
// If we didn't see this declaration before, and it's an acceptable
18501862
// result, add it to the list.
1851-
// declaration to the list.
18521863
if (knownDecls.insert(decl).second &&
18531864
isAcceptableLookupResult(dc, options, decl,
18541865
/*onlyCompleteObjectInits=*/false))

lib/ClangImporter/ImportDecl.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4537,7 +4537,8 @@ namespace {
45374537
bodyParams, resultTy,
45384538
async, throws, dc, decl);
45394539

4540-
result->setAccess(getOverridableAccessLevel(dc));
4540+
result->setAccess(decl->isDirectMethod() ? AccessLevel::Public
4541+
: getOverridableAccessLevel(dc));
45414542

45424543
// Optional methods in protocols.
45434544
if (decl->getImplementationControl() == clang::ObjCMethodDecl::Optional &&
@@ -5289,8 +5290,9 @@ namespace {
52895290
}
52905291

52915292
auto type = importedType.getType();
5292-
auto result = Impl.createDeclWithClangNode<VarDecl>(decl,
5293-
getOverridableAccessLevel(dc),
5293+
const auto access = decl->isDirectProperty() ? AccessLevel::Public
5294+
: getOverridableAccessLevel(dc);
5295+
auto result = Impl.createDeclWithClangNode<VarDecl>(decl, access,
52945296
/*IsStatic*/decl->isClassProperty(), VarDecl::Introducer::Var,
52955297
Impl.importSourceLoc(decl->getLocation()), name, dc);
52965298
result->setInterfaceType(type);
@@ -6981,7 +6983,13 @@ SwiftDeclConverter::importSubscript(Decl *decl,
69816983
bodyParams, decl->getLoc(),
69826984
elementTy, dc,
69836985
getter->getClangNode());
6984-
const auto access = getOverridableAccessLevel(dc);
6986+
6987+
bool IsObjCDirect = false;
6988+
if (auto objCDecl = dyn_cast<clang::ObjCMethodDecl>(getter->getClangDecl())) {
6989+
IsObjCDirect = objCDecl->isDirectMethod();
6990+
}
6991+
const auto access = IsObjCDirect ? AccessLevel::Public
6992+
: getOverridableAccessLevel(dc);
69856993
subscript->setAccess(access);
69866994
subscript->setSetterAccess(access);
69876995

@@ -7835,10 +7843,13 @@ void ClangImporter::Implementation::importAttributes(
78357843

78367844
if (auto method = dyn_cast<clang::ObjCMethodDecl>(ClangDecl)) {
78377845
if (method->isDirectMethod() && !AnyUnavailable) {
7838-
auto attr = AvailableAttr::createPlatformAgnostic(
7839-
C, "", "", PlatformAgnosticAvailabilityKind::UnavailableInSwift);
7840-
MappedDecl->getAttrs().add(attr);
7841-
AnyUnavailable = true;
7846+
assert(isa<AbstractFunctionDecl>(MappedDecl) &&
7847+
"objc_direct declarations are expected to be an AbstractFunctionDecl");
7848+
MappedDecl->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true));
7849+
if (auto accessorDecl = dyn_cast<AccessorDecl>(MappedDecl)) {
7850+
auto attr = new (C) FinalAttr(/*isImplicit=*/true);
7851+
accessorDecl->getStorage()->getAttrs().add(attr);
7852+
}
78427853
}
78437854
}
78447855

lib/IRGen/GenDecl.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,12 +2860,18 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
28602860
// the insert-before point.
28612861
llvm::Constant *clangAddr = nullptr;
28622862
if (auto clangDecl = f->getClangDecl()) {
2863-
auto globalDecl = getClangGlobalDeclForFunction(clangDecl);
2864-
clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition);
2863+
// If we have an Objective-C Clang declaration, it must be a direct
2864+
// method and we want to generate the IR declaration ourselves.
2865+
if (auto objcDecl = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
2866+
assert(objcDecl->isDirectMethod());
2867+
} else {
2868+
auto globalDecl = getClangGlobalDeclForFunction(clangDecl);
2869+
clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition);
28652870

2866-
if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(clangDecl)) {
2867-
clangAddr =
2868-
emitCXXConstructorThunkIfNeeded(*this, f, ctor, entity, clangAddr);
2871+
if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(clangDecl)) {
2872+
clangAddr =
2873+
emitCXXConstructorThunkIfNeeded(*this, f, ctor, entity, clangAddr);
2874+
}
28692875
}
28702876
}
28712877

lib/IRGen/GenObjC.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,14 @@ Callee irgen::getObjCMethodCallee(IRGenFunction &IGF,
661661
return Callee(std::move(info), fn, receiverValue, selectorValue);
662662
}
663663

664+
Callee irgen::getObjCDirectMethodCallee(CalleeInfo &&info, const FunctionPointer &fn,
665+
llvm::Value *selfValue) {
666+
// Direct calls to Objective-C methods have a selector value of `undef`.
667+
auto selectorType = fn.getFunctionType()->getParamType(1);
668+
auto selectorValue = llvm::UndefValue::get(selectorType);
669+
return Callee(std::move(info), fn, selfValue, selectorValue);
670+
}
671+
664672
/// Call [self allocWithZone: nil].
665673
llvm::Value *irgen::emitObjCAllocObjectCall(IRGenFunction &IGF,
666674
llvm::Value *self,

lib/IRGen/GenObjC.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ namespace irgen {
8888
Callee getObjCMethodCallee(IRGenFunction &IGF, const ObjCMethod &method,
8989
llvm::Value *selfValue, CalleeInfo &&info);
9090

91+
/// Prepare a callee for an Objective-C method with the `objc_direct` attribute.
92+
Callee getObjCDirectMethodCallee(CalleeInfo &&info, const FunctionPointer &fn,
93+
llvm::Value *selfValue);
94+
9195
/// Emit a partial application of an Objective-C method to its 'self'
9296
/// argument.
9397
void emitObjCPartialApplication(IRGenFunction &IGF,

lib/IRGen/IRGenSIL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,6 +2524,10 @@ Callee LoweredValue::getCallee(IRGenFunction &IGF,
25242524
switch (kind) {
25252525
case Kind::FunctionPointer: {
25262526
auto &fn = getFunctionPointer();
2527+
if (calleeInfo.OrigFnType->getRepresentation() ==
2528+
SILFunctionTypeRepresentation::ObjCMethod) {
2529+
return getObjCDirectMethodCallee(std::move(calleeInfo), fn, selfValue);
2530+
}
25272531
return Callee(std::move(calleeInfo), fn, selfValue);
25282532
}
25292533

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/SIL/SILLinkage.h"
2222
#include "swift/SIL/SILLocation.h"
2323
#include "swift/SILOptimizer/Utils/SpecializationMangler.h"
24+
#include "clang/AST/ASTContext.h"
2425
#include "clang/AST/Attr.h"
2526
#include "clang/AST/Decl.h"
2627
#include "clang/AST/DeclCXX.h"
@@ -712,6 +713,16 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
712713
return SS.str();
713714
}
714715
return namedClangDecl->getName().str();
716+
} else if (auto objcDecl = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
717+
if (objcDecl->isDirectMethod()) {
718+
std::string storage;
719+
llvm::raw_string_ostream SS(storage);
720+
clang::ASTContext &ctx = clangDecl->getASTContext();
721+
std::unique_ptr<clang::MangleContext> mangler(ctx.createMangleContext());
722+
mangler->mangleObjCMethodName(objcDecl, SS, /*includePrefixByte=*/true,
723+
/*includeCategoryNamespace=*/false);
724+
return SS.str();
725+
}
715726
}
716727
}
717728
}

lib/SILGen/SILGenApply.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "swift/SIL/SILArgument.h"
4040
#include "clang/AST/DeclCXX.h"
4141
#include "llvm/Support/Compiler.h"
42+
#include "clang/AST/DeclObjC.h"
4243

4344
using namespace swift;
4445
using namespace Lowering;
@@ -1059,7 +1060,18 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
10591060
auto constant = SILDeclRef(afd).asForeign(requiresForeignEntryPoint(afd));
10601061

10611062
auto subs = e->getDeclRef().getSubstitutions();
1062-
setCallee(Callee::forClassMethod(SGF, constant, subs, e));
1063+
1064+
bool isObjCDirect = false;
1065+
if (auto objcDecl = dyn_cast_or_null<clang::ObjCMethodDecl>(
1066+
afd->getClangDecl())) {
1067+
isObjCDirect = objcDecl->isDirectMethod();
1068+
}
1069+
1070+
if (isObjCDirect) {
1071+
setCallee(Callee::forDirect(SGF, constant, subs, e));
1072+
} else {
1073+
setCallee(Callee::forClassMethod(SGF, constant, subs, e));
1074+
}
10631075
}
10641076

10651077
//
@@ -5112,8 +5124,14 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &SGF,
51125124
}
51135125
}
51145126

5127+
bool isObjCDirect = false;
5128+
if (auto objcDecl = dyn_cast_or_null<clang::ObjCMethodDecl>(
5129+
decl->getClangDecl())) {
5130+
isObjCDirect = objcDecl->isDirectMethod();
5131+
}
5132+
51155133
// Dispatch in a struct/enum or to a final method is always direct.
5116-
if (!isClassDispatch)
5134+
if (!isClassDispatch || isObjCDirect)
51175135
return Callee::forDirect(SGF, constant, subs, loc);
51185136

51195137
// Otherwise, if we have a non-final class dispatch to a normal method,

lib/Sema/LookupVisibleDecls.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#include "TypeChecker.h"
19+
#include "clang/AST/DeclObjC.h"
1920
#include "swift/AST/ASTContext.h"
2021
#include "swift/AST/GenericSignature.h"
2122
#include "swift/AST/GenericSignatureBuilder.h"
@@ -314,6 +315,17 @@ static void doDynamicLookup(VisibleDeclConsumer &Consumer,
314315
if (!D->isObjC())
315316
return;
316317

318+
// If the declaration is objc_direct, it cannot be called dynamically.
319+
if (auto clangDecl = D->getClangDecl()) {
320+
if (auto objCMethod = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
321+
if (objCMethod->isDirectMethod())
322+
return;
323+
} else if (auto objCProperty = dyn_cast<clang::ObjCPropertyDecl>(clangDecl)) {
324+
if (objCProperty->isDirectProperty())
325+
return;
326+
}
327+
}
328+
317329
if (D->isRecursiveValidation())
318330
return;
319331

test/ClangImporter/Inputs/objc_direct.h

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)