@@ -2224,6 +2224,96 @@ class CGObjCObjFW: public CGObjCGNU {
2224
2224
return ClassSymbol;
2225
2225
}
2226
2226
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
+
2227
2317
public:
2228
2318
CGObjCObjFW (CodeGenModule &Mod): CGObjCGNU(Mod, 9 , 3 ) {
2229
2319
// IMP objc_msg_lookup(id, SEL);
0 commit comments