@@ -756,12 +756,13 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
756756 if (OMD->hasAttr <NoDebugAttr>())
757757 DebugInfo = nullptr ; // disable debug info indefinitely for this function
758758
759- llvm::Function *Fn = CGM.getObjCRuntime ().GenerateMethod (OMD, CD);
759+ bool isInner = CGM.shouldHaveNilCheckThunk (OMD) && !InnerFn;
760+ llvm::Function *Fn = CGM.getObjCRuntime ().GenerateMethod (OMD, CD, !isInner);
760761
761762 const CGFunctionInfo &FI = CGM.getTypes ().arrangeObjCMethodDeclaration (OMD);
762763 if (OMD->isDirectMethod ()) {
763764 Fn->setVisibility (llvm::Function::HiddenVisibility);
764- CGM.SetLLVMFunctionAttributes (OMD, FI, Fn, /* IsThunk=*/ false );
765+ CGM.SetLLVMFunctionAttributes (OMD, FI, Fn, /* IsThunk=*/ InnerFn );
765766 CGM.SetLLVMFunctionAttributesForDefinition (OMD, Fn);
766767 } else {
767768 CGM.SetInternalFunctionAttributes (OMD, Fn, FI);
@@ -780,11 +781,21 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
780781 OMD->getLocation (), StartLoc);
781782
782783 if (OMD->isDirectMethod ()) {
783- // This function is a direct call, it has to implement a nil check
784- // on entry.
785- //
786- // TODO: possibly have several entry points to elide the check
787- CGM.getObjCRuntime ().GenerateDirectMethodPrologue (*this , Fn, OMD, CD);
784+ if (CGM.getLangOpts ().ObjCRuntime .isNeXTFamily ()) {
785+ // Having `InnerFn` indicates that we are generating a nil check thunk.
786+ // In that case our job is done here.
787+ if (InnerFn)
788+ return ;
789+ if (CGM.shouldHaveNilCheckThunk (OMD))
790+ // Go generate a nil check thunk around `Fn`
791+ CodeGenFunction (CGM, /* InnerFn=*/ Fn).GenerateObjCDirectThunk (OMD, CD);
792+ else
793+ CGM.getObjCRuntime ().GenerateObjCDirectNilCheck (*this , OMD, CD);
794+ CGM.getObjCRuntime ().GenerateCmdIfNecessary (*this , OMD);
795+ } else {
796+ // For GNU family, since GNU Step2 also supports direct methods now.
797+ CGM.getObjCRuntime ().GenerateDirectMethodPrologue (*this , Fn, OMD, CD);
798+ }
788799 }
789800
790801 // In ARC, certain methods get an extra cleanup.
@@ -1637,6 +1648,44 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
16371648 FinishFunction (OMD->getEndLoc ());
16381649}
16391650
1651+ void CodeGenFunction::GenerateObjCDirectThunk (const ObjCMethodDecl *OMD,
1652+ const ObjCContainerDecl *CD) {
1653+ assert (InnerFn && CGM.shouldHaveNilCheckThunk (OMD) &&
1654+ " Should only generate wrapper when the flag is set." );
1655+ StartObjCMethod (OMD, CD);
1656+
1657+ // Manually pop all the clean up that doesn't need to happen in the outer
1658+ // function. InnerFn will do this for us.
1659+ while (EHStack.stable_begin () != PrologueCleanupDepth)
1660+ EHStack.popCleanup ();
1661+
1662+ // Generate a nil check.
1663+ CGM.getObjCRuntime ().GenerateObjCDirectNilCheck (*this , OMD, CD);
1664+ // Call the InnerFn and pass the return value
1665+ SmallVector<llvm::Value *> Args (CurFn->arg_size ());
1666+ std::transform (CurFn->arg_begin (), CurFn->arg_end (), Args.begin (),
1667+ [](llvm::Argument &arg) { return &arg; });
1668+
1669+ // This will be optimized into a tail call.
1670+ auto *CallInst = EmitCallOrInvoke (InnerFn, Args);
1671+ // Preserve the inner function's attributes to the call instruction.
1672+ CallInst->setAttributes (InnerFn->getAttributes ());
1673+ llvm::Value *RetVal = CallInst;
1674+
1675+ // If `AutoreleaseResult` is set, the return value is not void.
1676+ if (AutoreleaseResult)
1677+ RetVal = EmitARCRetainAutoreleasedReturnValue (RetVal);
1678+
1679+ // This excessive store is totally unnecessary.
1680+ // But `FinishFunction` really wants us to store the result so it can
1681+ // clean up the function properly.
1682+ // The unnecessary store-load of the ret value will be optimized out anyway.
1683+ if (!CurFn->getReturnType ()->isVoidTy ())
1684+ Builder.CreateStore (RetVal, ReturnValue);
1685+
1686+ // Nil check's end location is the function's start location.
1687+ FinishFunction (OMD->getBeginLoc ());
1688+ }
16401689namespace {
16411690 struct DestroyIvar final : EHScopeStack::Cleanup {
16421691 private:
0 commit comments