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