Skip to content

Commit a187060

Browse files
authored
Allow direct dispatch for the ObjFW runtime (llvm#126382)
Allow direct dispatch for the ObjFW runtime
1 parent 206b42c commit a187060

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

clang/include/clang/Basic/ObjCRuntime.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ class ObjCRuntime {
473473
case GCC: return false;
474474
case GNUstep:
475475
return (getVersion() >= VersionTuple(2, 2));
476-
case ObjFW: return false;
476+
case ObjFW: return true;
477477
}
478478
llvm_unreachable("bad kind");
479479
}

clang/lib/CodeGen/CGObjCGNU.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2224,6 +2224,96 @@ class CGObjCObjFW: public CGObjCGNU {
22242224
return ClassSymbol;
22252225
}
22262226

2227+
void GenerateDirectMethodPrologue(
2228+
CodeGenFunction &CGF, llvm::Function *Fn, const ObjCMethodDecl *OMD,
2229+
const ObjCContainerDecl *CD) override {
2230+
auto &Builder = CGF.Builder;
2231+
bool ReceiverCanBeNull = true;
2232+
auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl());
2233+
auto selfValue = Builder.CreateLoad(selfAddr);
2234+
2235+
// Generate:
2236+
//
2237+
// /* for class methods only to force class lazy initialization */
2238+
// self = [self self];
2239+
//
2240+
// /* unless the receiver is never NULL */
2241+
// if (self == nil) {
2242+
// return (ReturnType){ };
2243+
// }
2244+
//
2245+
// _cmd = @selector(...)
2246+
// ...
2247+
2248+
if (OMD->isClassMethod()) {
2249+
const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
2250+
assert(
2251+
OID &&
2252+
"GenerateDirectMethod() should be called with the Class Interface");
2253+
Selector SelfSel = GetNullarySelector("self", CGM.getContext());
2254+
auto ResultType = CGF.getContext().getObjCIdType();
2255+
RValue result;
2256+
CallArgList Args;
2257+
2258+
// TODO: If this method is inlined, the caller might know that `self` is
2259+
// already initialized; for example, it might be an ordinary Objective-C
2260+
// method which always receives an initialized `self`, or it might have
2261+
// just forced initialization on its own.
2262+
//
2263+
// We should find a way to eliminate this unnecessary initialization in
2264+
// such cases in LLVM.
2265+
result = GeneratePossiblySpecializedMessageSend(
2266+
CGF, ReturnValueSlot(), ResultType, SelfSel, selfValue, Args, OID,
2267+
nullptr, true);
2268+
Builder.CreateStore(result.getScalarVal(), selfAddr);
2269+
2270+
// Nullable `Class` expressions cannot be messaged with a direct method
2271+
// so the only reason why the receive can be null would be because
2272+
// of weak linking.
2273+
ReceiverCanBeNull = isWeakLinkedClass(OID);
2274+
}
2275+
2276+
if (ReceiverCanBeNull) {
2277+
llvm::BasicBlock *SelfIsNilBlock =
2278+
CGF.createBasicBlock("objc_direct_method.self_is_nil");
2279+
llvm::BasicBlock *ContBlock =
2280+
CGF.createBasicBlock("objc_direct_method.cont");
2281+
2282+
// if (self == nil) {
2283+
auto selfTy = cast<llvm::PointerType>(selfValue->getType());
2284+
auto Zero = llvm::ConstantPointerNull::get(selfTy);
2285+
2286+
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
2287+
Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero),
2288+
SelfIsNilBlock, ContBlock,
2289+
MDHelper.createUnlikelyBranchWeights());
2290+
2291+
CGF.EmitBlock(SelfIsNilBlock);
2292+
2293+
// return (ReturnType){ };
2294+
auto retTy = OMD->getReturnType();
2295+
Builder.SetInsertPoint(SelfIsNilBlock);
2296+
if (!retTy->isVoidType()) {
2297+
CGF.EmitNullInitialization(CGF.ReturnValue, retTy);
2298+
}
2299+
CGF.EmitBranchThroughCleanup(CGF.ReturnBlock);
2300+
// }
2301+
2302+
// rest of the body
2303+
CGF.EmitBlock(ContBlock);
2304+
Builder.SetInsertPoint(ContBlock);
2305+
}
2306+
2307+
// only synthesize _cmd if it's referenced
2308+
if (OMD->getCmdDecl()->isUsed()) {
2309+
// `_cmd` is not a parameter to direct methods, so storage must be
2310+
// explicitly declared for it.
2311+
CGF.EmitVarDecl(*OMD->getCmdDecl());
2312+
Builder.CreateStore(GetSelector(CGF, OMD),
2313+
CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
2314+
}
2315+
}
2316+
22272317
public:
22282318
CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
22292319
// IMP objc_msg_lookup(id, SEL);

0 commit comments

Comments
 (0)