@@ -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+
22272317public:
22282318 CGObjCObjFW (CodeGenModule &Mod): CGObjCGNU(Mod, 9 , 3 ) {
22292319 // IMP objc_msg_lookup(id, SEL);
0 commit comments