Skip to content

Commit ddc24b9

Browse files
committed
Allow direct dispatch for the ObjFW runtime
1 parent 564b9b7 commit ddc24b9

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
@@ -2222,6 +2222,96 @@ class CGObjCObjFW: public CGObjCGNU {
22222222
return ClassSymbol;
22232223
}
22242224

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

0 commit comments

Comments
 (0)