Skip to content

Commit 9b07617

Browse files
committed
Allow direct dispatch for the ObjFW runtime >= 1.3
1 parent 564b9b7 commit 9b07617

File tree

2 files changed

+106
-108
lines changed

2 files changed

+106
-108
lines changed

clang/include/clang/Basic/ObjCRuntime.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,8 @@ class ObjCRuntime {
473473
case GCC: return false;
474474
case GNUstep:
475475
return (getVersion() >= VersionTuple(2, 2));
476-
case ObjFW: return false;
476+
case ObjFW:
477+
return (getVersion() >= VersionTuple(1, 3));
477478
}
478479
llvm_unreachable("bad kind");
479480
}

clang/lib/CodeGen/CGObjCGNU.cpp

Lines changed: 104 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,112 +2029,6 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
20292029
llvm::StructType::get(CGM.getLLVMContext(),
20302030
{ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty });
20312031
}
2032-
2033-
void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
2034-
const ObjCMethodDecl *OMD,
2035-
const ObjCContainerDecl *CD) override {
2036-
auto &Builder = CGF.Builder;
2037-
bool ReceiverCanBeNull = true;
2038-
auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl());
2039-
auto selfValue = Builder.CreateLoad(selfAddr);
2040-
2041-
// Generate:
2042-
//
2043-
// /* unless the receiver is never NULL */
2044-
// if (self == nil) {
2045-
// return (ReturnType){ };
2046-
// }
2047-
//
2048-
// /* for class methods only to force class lazy initialization */
2049-
// if (!__objc_{class}_initialized)
2050-
// {
2051-
// objc_send_initialize(class);
2052-
// __objc_{class}_initialized = 1;
2053-
// }
2054-
//
2055-
// _cmd = @selector(...)
2056-
// ...
2057-
2058-
if (OMD->isClassMethod()) {
2059-
const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
2060-
2061-
// Nullable `Class` expressions cannot be messaged with a direct method
2062-
// so the only reason why the receive can be null would be because
2063-
// of weak linking.
2064-
ReceiverCanBeNull = isWeakLinkedClass(OID);
2065-
}
2066-
2067-
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
2068-
if (ReceiverCanBeNull) {
2069-
llvm::BasicBlock *SelfIsNilBlock =
2070-
CGF.createBasicBlock("objc_direct_method.self_is_nil");
2071-
llvm::BasicBlock *ContBlock =
2072-
CGF.createBasicBlock("objc_direct_method.cont");
2073-
2074-
// if (self == nil) {
2075-
auto selfTy = cast<llvm::PointerType>(selfValue->getType());
2076-
auto Zero = llvm::ConstantPointerNull::get(selfTy);
2077-
2078-
Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero),
2079-
SelfIsNilBlock, ContBlock,
2080-
MDHelper.createUnlikelyBranchWeights());
2081-
2082-
CGF.EmitBlock(SelfIsNilBlock);
2083-
2084-
// return (ReturnType){ };
2085-
auto retTy = OMD->getReturnType();
2086-
Builder.SetInsertPoint(SelfIsNilBlock);
2087-
if (!retTy->isVoidType()) {
2088-
CGF.EmitNullInitialization(CGF.ReturnValue, retTy);
2089-
}
2090-
CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
2091-
// }
2092-
2093-
// rest of the body
2094-
CGF.EmitBlock(ContBlock);
2095-
Builder.SetInsertPoint(ContBlock);
2096-
}
2097-
2098-
if (OMD->isClassMethod()) {
2099-
// Prefix of the class type.
2100-
auto *classStart =
2101-
llvm::StructType::get(PtrTy, PtrTy, PtrTy, LongTy, LongTy);
2102-
auto &astContext = CGM.getContext();
2103-
// FIXME: The following few lines up to and including the call to
2104-
// `CreateLoad` were known to miscompile when MSVC 19.40.33813 is used
2105-
// to build Clang. When the bug is fixed in future MSVC releases, we
2106-
// should revert these lines to their previous state. See discussion in
2107-
// https://github.com/llvm/llvm-project/pull/102681
2108-
llvm::Value *Val = Builder.CreateStructGEP(classStart, selfValue, 4);
2109-
auto Align = CharUnits::fromQuantity(
2110-
astContext.getTypeAlign(astContext.UnsignedLongTy));
2111-
auto flags = Builder.CreateLoad(Address{Val, LongTy, Align});
2112-
auto isInitialized =
2113-
Builder.CreateAnd(flags, ClassFlags::ClassFlagInitialized);
2114-
llvm::BasicBlock *notInitializedBlock =
2115-
CGF.createBasicBlock("objc_direct_method.class_uninitialized");
2116-
llvm::BasicBlock *initializedBlock =
2117-
CGF.createBasicBlock("objc_direct_method.class_initialized");
2118-
Builder.CreateCondBr(Builder.CreateICmpEQ(isInitialized, Zeros[0]),
2119-
notInitializedBlock, initializedBlock,
2120-
MDHelper.createUnlikelyBranchWeights());
2121-
CGF.EmitBlock(notInitializedBlock);
2122-
Builder.SetInsertPoint(notInitializedBlock);
2123-
CGF.EmitRuntimeCall(SentInitializeFn, selfValue);
2124-
Builder.CreateBr(initializedBlock);
2125-
CGF.EmitBlock(initializedBlock);
2126-
Builder.SetInsertPoint(initializedBlock);
2127-
}
2128-
2129-
// only synthesize _cmd if it's referenced
2130-
if (OMD->getCmdDecl()->isUsed()) {
2131-
// `_cmd` is not a parameter to direct methods, so storage must be
2132-
// explicitly declared for it.
2133-
CGF.EmitVarDecl(*OMD->getCmdDecl());
2134-
Builder.CreateStore(GetSelector(CGF, OMD),
2135-
CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
2136-
}
2137-
}
21382032
};
21392033

21402034
const char *const CGObjCGNUstep2::SectionsBaseNames[8] =
@@ -4121,7 +4015,110 @@ void CGObjCGNU::GenerateDirectMethodPrologue(CodeGenFunction &CGF,
41214015
llvm::Function *Fn,
41224016
const ObjCMethodDecl *OMD,
41234017
const ObjCContainerDecl *CD) {
4124-
// GNU runtime doesn't support direct calls at this time
4018+
if (!CGM.getLangOpts().ObjCRuntime.allowsDirectDispatch())
4019+
return;
4020+
4021+
auto &Builder = CGF.Builder;
4022+
bool ReceiverCanBeNull = true;
4023+
auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl());
4024+
auto selfValue = Builder.CreateLoad(selfAddr);
4025+
4026+
// Generate:
4027+
//
4028+
// /* unless the receiver is never NULL */
4029+
// if (self == nil) {
4030+
// return (ReturnType){ };
4031+
// }
4032+
//
4033+
// /* for class methods only to force class lazy initialization */
4034+
// if (!__objc_{class}_initialized)
4035+
// {
4036+
// objc_send_initialize(class);
4037+
// __objc_{class}_initialized = 1;
4038+
// }
4039+
//
4040+
// _cmd = @selector(...)
4041+
// ...
4042+
4043+
if (OMD->isClassMethod()) {
4044+
const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
4045+
4046+
// Nullable `Class` expressions cannot be messaged with a direct method
4047+
// so the only reason why the receive can be null would be because
4048+
// of weak linking.
4049+
ReceiverCanBeNull = isWeakLinkedClass(OID);
4050+
}
4051+
4052+
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
4053+
if (ReceiverCanBeNull) {
4054+
llvm::BasicBlock *SelfIsNilBlock =
4055+
CGF.createBasicBlock("objc_direct_method.self_is_nil");
4056+
llvm::BasicBlock *ContBlock =
4057+
CGF.createBasicBlock("objc_direct_method.cont");
4058+
4059+
// if (self == nil) {
4060+
auto selfTy = cast<llvm::PointerType>(selfValue->getType());
4061+
auto Zero = llvm::ConstantPointerNull::get(selfTy);
4062+
4063+
Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero),
4064+
SelfIsNilBlock, ContBlock,
4065+
MDHelper.createUnlikelyBranchWeights());
4066+
4067+
CGF.EmitBlock(SelfIsNilBlock);
4068+
4069+
// return (ReturnType){ };
4070+
auto retTy = OMD->getReturnType();
4071+
Builder.SetInsertPoint(SelfIsNilBlock);
4072+
if (!retTy->isVoidType()) {
4073+
CGF.EmitNullInitialization(CGF.ReturnValue, retTy);
4074+
}
4075+
CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
4076+
// }
4077+
4078+
// rest of the body
4079+
CGF.EmitBlock(ContBlock);
4080+
Builder.SetInsertPoint(ContBlock);
4081+
}
4082+
4083+
if (OMD->isClassMethod()) {
4084+
// Prefix of the class type.
4085+
auto *classStart =
4086+
llvm::StructType::get(PtrTy, PtrTy, PtrTy, LongTy, LongTy);
4087+
auto &astContext = CGM.getContext();
4088+
// FIXME: The following few lines up to and including the call to
4089+
// `CreateLoad` were known to miscompile when MSVC 19.40.33813 is used
4090+
// to build Clang. When the bug is fixed in future MSVC releases, we
4091+
// should revert these lines to their previous state. See discussion in
4092+
// https://github.com/llvm/llvm-project/pull/102681
4093+
llvm::Value *Val = Builder.CreateStructGEP(classStart, selfValue, 4);
4094+
auto Align = CharUnits::fromQuantity(
4095+
astContext.getTypeAlign(astContext.UnsignedLongTy));
4096+
auto flags = Builder.CreateLoad(Address{Val, LongTy, Align});
4097+
auto isInitialized =
4098+
Builder.CreateAnd(flags, ClassFlags::ClassFlagInitialized);
4099+
llvm::BasicBlock *notInitializedBlock =
4100+
CGF.createBasicBlock("objc_direct_method.class_uninitialized");
4101+
llvm::BasicBlock *initializedBlock =
4102+
CGF.createBasicBlock("objc_direct_method.class_initialized");
4103+
Builder.CreateCondBr(Builder.CreateICmpEQ(isInitialized, Zeros[0]),
4104+
notInitializedBlock, initializedBlock,
4105+
MDHelper.createUnlikelyBranchWeights());
4106+
CGF.EmitBlock(notInitializedBlock);
4107+
Builder.SetInsertPoint(notInitializedBlock);
4108+
CGF.EmitRuntimeCall(SentInitializeFn, selfValue);
4109+
Builder.CreateBr(initializedBlock);
4110+
CGF.EmitBlock(initializedBlock);
4111+
Builder.SetInsertPoint(initializedBlock);
4112+
}
4113+
4114+
// only synthesize _cmd if it's referenced
4115+
if (OMD->getCmdDecl()->isUsed()) {
4116+
// `_cmd` is not a parameter to direct methods, so storage must be
4117+
// explicitly declared for it.
4118+
CGF.EmitVarDecl(*OMD->getCmdDecl());
4119+
Builder.CreateStore(GetSelector(CGF, OMD),
4120+
CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
4121+
}
41254122
}
41264123

41274124
llvm::FunctionCallee CGObjCGNU::GetPropertyGetFunction() {

0 commit comments

Comments
 (0)