18
18
#include " CGObjCRuntime.h"
19
19
#include " CodeGenFunction.h"
20
20
#include " CodeGenModule.h"
21
+ #include " CodeGenTypes.h"
22
+ #include " SanitizerMetadata.h"
21
23
#include " clang/AST/ASTContext.h"
22
24
#include " clang/AST/Attr.h"
23
25
#include " clang/AST/Decl.h"
@@ -597,6 +599,10 @@ class CGObjCGNU : public CGObjCRuntime {
597
599
598
600
llvm::Function *GenerateMethod (const ObjCMethodDecl *OMD,
599
601
const ObjCContainerDecl *CD) override ;
602
+
603
+ // Map to unify direct method definitions.
604
+ llvm::DenseMap<const ObjCMethodDecl *, llvm::Function *>
605
+ DirectMethodDefinitions;
600
606
void GenerateDirectMethodPrologue (CodeGenFunction &CGF, llvm::Function *Fn,
601
607
const ObjCMethodDecl *OMD,
602
608
const ObjCContainerDecl *CD) override ;
@@ -917,6 +923,14 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
917
923
ClassAliasSection,
918
924
ConstantStringSection
919
925
};
926
+ // / The subset of `objc_class_flags` used at compile time.
927
+ enum ClassFlags {
928
+ // / This is a metaclass
929
+ ClassFlagMeta = (1 << 0 ),
930
+ // / This class has been initialised by the runtime (+initialize has been
931
+ // / sent if necessary).
932
+ ClassFlagInitialized = (1 << 8 ),
933
+ };
920
934
static const char *const SectionsBaseNames[8 ];
921
935
static const char *const PECOFFSectionsBaseNames[8 ];
922
936
template <SectionKind K>
@@ -932,6 +946,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
932
946
// / structure describing the receiver and the class, and a selector as
933
947
// / arguments. Returns the IMP for the corresponding method.
934
948
LazyRuntimeFunction MsgLookupSuperFn;
949
+ // / Function to ensure that +initialize is sent to a class.
950
+ LazyRuntimeFunction SentInitializeFn;
935
951
// / A flag indicating if we've emitted at least one protocol.
936
952
// / If we haven't, then we need to emit an empty protocol, to ensure that the
937
953
// / __start__objc_protocols and __stop__objc_protocols sections exist.
@@ -1719,7 +1735,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
1719
1735
metaclassFields.addInt (LongTy, 0 );
1720
1736
// unsigned long info;
1721
1737
// objc_class_flag_meta
1722
- metaclassFields.addInt (LongTy, 1 );
1738
+ metaclassFields.addInt (LongTy, ClassFlags::ClassFlagMeta );
1723
1739
// long instance_size;
1724
1740
// Setting this to zero is consistent with the older ABI, but it might be
1725
1741
// more sensible to set this to sizeof(struct objc_class)
@@ -1993,6 +2009,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
1993
2009
CGObjCGNUstep2 (CodeGenModule &Mod) : CGObjCGNUstep(Mod, 10 , 4 , 2 ) {
1994
2010
MsgLookupSuperFn.init (&CGM, " objc_msg_lookup_super" , IMPTy,
1995
2011
PtrToObjCSuperTy, SelectorTy);
2012
+ SentInitializeFn.init (&CGM, " objc_send_initialize" ,
2013
+ llvm::Type::getVoidTy (VMContext), IdTy);
1996
2014
// struct objc_property
1997
2015
// {
1998
2016
// const char *name;
@@ -2006,6 +2024,106 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
2006
2024
{ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty });
2007
2025
}
2008
2026
2027
+ void GenerateDirectMethodPrologue (CodeGenFunction &CGF, llvm::Function *Fn,
2028
+ const ObjCMethodDecl *OMD,
2029
+ const ObjCContainerDecl *CD) override {
2030
+ auto &Builder = CGF.Builder ;
2031
+ bool ReceiverCanBeNull = true ;
2032
+ auto selfAddr = CGF.GetAddrOfLocalVar (OMD->getSelfDecl ());
2033
+ auto selfValue = Builder.CreateLoad (selfAddr);
2034
+
2035
+ // Generate:
2036
+ //
2037
+ // /* unless the receiver is never NULL */
2038
+ // if (self == nil) {
2039
+ // return (ReturnType){ };
2040
+ // }
2041
+ //
2042
+ // /* for class methods only to force class lazy initialization */
2043
+ // if (!__objc_{class}_initialized)
2044
+ // {
2045
+ // objc_send_initialize(class);
2046
+ // __objc_{class}_initialized = 1;
2047
+ // }
2048
+ //
2049
+ // _cmd = @selector(...)
2050
+ // ...
2051
+
2052
+ if (OMD->isClassMethod ()) {
2053
+ const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD);
2054
+
2055
+ // Nullable `Class` expressions cannot be messaged with a direct method
2056
+ // so the only reason why the receive can be null would be because
2057
+ // of weak linking.
2058
+ ReceiverCanBeNull = isWeakLinkedClass (OID);
2059
+ }
2060
+
2061
+ llvm::MDBuilder MDHelper (CGM.getLLVMContext ());
2062
+ if (ReceiverCanBeNull) {
2063
+ llvm::BasicBlock *SelfIsNilBlock =
2064
+ CGF.createBasicBlock (" objc_direct_method.self_is_nil" );
2065
+ llvm::BasicBlock *ContBlock =
2066
+ CGF.createBasicBlock (" objc_direct_method.cont" );
2067
+
2068
+ // if (self == nil) {
2069
+ auto selfTy = cast<llvm::PointerType>(selfValue->getType ());
2070
+ auto Zero = llvm::ConstantPointerNull::get (selfTy);
2071
+
2072
+ Builder.CreateCondBr (Builder.CreateICmpEQ (selfValue, Zero),
2073
+ SelfIsNilBlock, ContBlock,
2074
+ MDHelper.createBranchWeights (1 , 1 << 20 ));
2075
+
2076
+ CGF.EmitBlock (SelfIsNilBlock);
2077
+
2078
+ // return (ReturnType){ };
2079
+ auto retTy = OMD->getReturnType ();
2080
+ Builder.SetInsertPoint (SelfIsNilBlock);
2081
+ if (!retTy->isVoidType ()) {
2082
+ CGF.EmitNullInitialization (CGF.ReturnValue , retTy);
2083
+ }
2084
+ CGF.EmitBranchThroughCleanup (CGF.ReturnBlock );
2085
+ // }
2086
+
2087
+ // rest of the body
2088
+ CGF.EmitBlock (ContBlock);
2089
+ Builder.SetInsertPoint (ContBlock);
2090
+ }
2091
+
2092
+ if (OMD->isClassMethod ()) {
2093
+ // Prefix of the class type.
2094
+ auto *classStart =
2095
+ llvm::StructType::get (PtrTy, PtrTy, PtrTy, LongTy, LongTy);
2096
+ auto &astContext = CGM.getContext ();
2097
+ auto flags = Builder.CreateLoad (
2098
+ Address{Builder.CreateStructGEP (classStart, selfValue, 4 ), LongTy,
2099
+ CharUnits::fromQuantity (
2100
+ astContext.getTypeAlign (astContext.UnsignedLongTy ))});
2101
+ auto isInitialized =
2102
+ Builder.CreateAnd (flags, ClassFlags::ClassFlagInitialized);
2103
+ llvm::BasicBlock *notInitializedBlock =
2104
+ CGF.createBasicBlock (" objc_direct_method.class_uninitialized" );
2105
+ llvm::BasicBlock *initializedBlock =
2106
+ CGF.createBasicBlock (" objc_direct_method.class_initialized" );
2107
+ Builder.CreateCondBr (Builder.CreateICmpEQ (isInitialized, Zeros[0 ]),
2108
+ notInitializedBlock, initializedBlock,
2109
+ MDHelper.createBranchWeights (1 , 1 << 20 ));
2110
+ CGF.EmitBlock (notInitializedBlock);
2111
+ Builder.SetInsertPoint (notInitializedBlock);
2112
+ CGF.EmitRuntimeCall (SentInitializeFn, selfValue);
2113
+ Builder.CreateBr (initializedBlock);
2114
+ CGF.EmitBlock (initializedBlock);
2115
+ Builder.SetInsertPoint (initializedBlock);
2116
+ }
2117
+
2118
+ // only synthesize _cmd if it's referenced
2119
+ if (OMD->getCmdDecl ()->isUsed ()) {
2120
+ // `_cmd` is not a parameter to direct methods, so storage must be
2121
+ // explicitly declared for it.
2122
+ CGF.EmitVarDecl (*OMD->getCmdDecl ());
2123
+ Builder.CreateStore (GetSelector (CGF, OMD),
2124
+ CGF.GetAddrOfLocalVar (OMD->getCmdDecl ()));
2125
+ }
2126
+ }
2009
2127
};
2010
2128
2011
2129
const char *const CGObjCGNUstep2::SectionsBaseNames[8 ] =
@@ -2649,13 +2767,18 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2649
2767
}
2650
2768
}
2651
2769
2770
+ bool isDirect = Method && Method->isDirectMethod ();
2771
+
2652
2772
IdTy = cast<llvm::PointerType>(CGM.getTypes ().ConvertType (ASTIdTy));
2653
2773
llvm::Value *cmd;
2654
- if (Method)
2655
- cmd = GetSelector (CGF, Method);
2656
- else
2657
- cmd = GetSelector (CGF, Sel);
2658
- cmd = EnforceType (Builder, cmd, SelectorTy);
2774
+ if (!isDirect) {
2775
+ if (Method)
2776
+ cmd = GetSelector (CGF, Method);
2777
+ else
2778
+ cmd = GetSelector (CGF, Sel);
2779
+ cmd = EnforceType (Builder, cmd, SelectorTy);
2780
+ }
2781
+
2659
2782
Receiver = EnforceType (Builder, Receiver, IdTy);
2660
2783
2661
2784
llvm::Metadata *impMD[] = {
@@ -2667,7 +2790,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2667
2790
2668
2791
CallArgList ActualArgs;
2669
2792
ActualArgs.add (RValue::get (Receiver), ASTIdTy);
2670
- ActualArgs.add (RValue::get (cmd), CGF.getContext ().getObjCSelType ());
2793
+ if (!isDirect)
2794
+ ActualArgs.add (RValue::get (cmd), CGF.getContext ().getObjCSelType ());
2671
2795
ActualArgs.addFrom (CallArgs);
2672
2796
2673
2797
MessageSendInfo MSI = getMessageSendInfo (Method, ResultType, ActualArgs);
@@ -2686,7 +2810,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2686
2810
// Rather than doing a whole target-specific analysis, we assume it
2687
2811
// only works for void, integer, and pointer types, and in all
2688
2812
// other cases we do an explicit nil check is emitted code. In
2689
- // addition to ensuring we produe a zero value for other types, this
2813
+ // addition to ensuring we produce a zero value for other types, this
2690
2814
// sidesteps the few outright CC incompatibilities we know about that
2691
2815
// could otherwise lead to crashes, like when a method is expected to
2692
2816
// return on the x87 floating point stack or adjust the stack pointer
@@ -2720,8 +2844,9 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2720
2844
// FIXME: we probably need a size limit here, but we've
2721
2845
// never imposed one before
2722
2846
} else {
2723
- // Otherwise, use an explicit check just to be sure.
2724
- requiresExplicitZeroResult = true ;
2847
+ // Otherwise, use an explicit check just to be sure, unless we're
2848
+ // calling a direct method, where the implementation does this for us.
2849
+ requiresExplicitZeroResult = !isDirect;
2725
2850
}
2726
2851
}
2727
2852
@@ -2765,10 +2890,14 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2765
2890
// Get the IMP to call
2766
2891
llvm::Value *imp;
2767
2892
2768
- // If we have non-legacy dispatch specified, we try using the objc_msgSend()
2769
- // functions. These are not supported on all platforms (or all runtimes on a
2770
- // given platform), so we
2771
- switch (CGM.getCodeGenOpts ().getObjCDispatchMethod ()) {
2893
+ // If this is a direct method, just emit it here.
2894
+ if (isDirect)
2895
+ imp = GenerateMethod (Method, Method->getClassInterface ());
2896
+ else
2897
+ // If we have non-legacy dispatch specified, we try using the
2898
+ // objc_msgSend() functions. These are not supported on all platforms
2899
+ // (or all runtimes on a given platform), so we
2900
+ switch (CGM.getCodeGenOpts ().getObjCDispatchMethod ()) {
2772
2901
case CodeGenOptions::Legacy:
2773
2902
imp = LookupIMP (CGF, Receiver, cmd, node, MSI);
2774
2903
break ;
@@ -2791,7 +2920,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2791
2920
llvm::FunctionType::get (IdTy, IdTy, true ), " objc_msgSend" )
2792
2921
.getCallee ();
2793
2922
}
2794
- }
2923
+ }
2795
2924
2796
2925
// Reset the receiver in case the lookup modified it
2797
2926
ActualArgs[0 ] = CallArg (RValue::get (Receiver), ASTIdTy);
@@ -2801,7 +2930,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2801
2930
llvm::CallBase *call;
2802
2931
CGCallee callee (CGCalleeInfo (), imp);
2803
2932
RValue msgRet = CGF.EmitCall (MSI.CallInfo , callee, Return, ActualArgs, &call);
2804
- call->setMetadata (msgSendMDKind, node);
2933
+ if (!isDirect)
2934
+ call->setMetadata (msgSendMDKind, node);
2805
2935
2806
2936
if (requiresNilReceiverCheck) {
2807
2937
llvm::BasicBlock *nonNilPathBB = CGF.Builder .GetInsertBlock ();
@@ -3924,14 +4054,50 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
3924
4054
CodeGenTypes &Types = CGM.getTypes ();
3925
4055
llvm::FunctionType *MethodTy =
3926
4056
Types.GetFunctionType (Types.arrangeObjCMethodDeclaration (OMD));
3927
- std::string FunctionName = getSymbolNameForMethod (OMD);
3928
-
3929
- llvm::Function *Method
3930
- = llvm::Function::Create (MethodTy,
3931
- llvm::GlobalValue::InternalLinkage,
3932
- FunctionName,
3933
- &TheModule);
3934
- return Method;
4057
+
4058
+ bool isDirect = OMD->isDirectMethod ();
4059
+ std::string FunctionName =
4060
+ getSymbolNameForMethod (OMD, /* include category*/ !isDirect);
4061
+
4062
+ if (!isDirect)
4063
+ return llvm::Function::Create (MethodTy,
4064
+ llvm::GlobalVariable::InternalLinkage,
4065
+ FunctionName, &TheModule);
4066
+
4067
+ auto *COMD = OMD->getCanonicalDecl ();
4068
+ auto I = DirectMethodDefinitions.find (COMD);
4069
+ llvm::Function *OldFn = nullptr , *Fn = nullptr ;
4070
+
4071
+ if (I == DirectMethodDefinitions.end ()) {
4072
+ auto *F =
4073
+ llvm::Function::Create (MethodTy, llvm::GlobalVariable::ExternalLinkage,
4074
+ FunctionName, &TheModule);
4075
+ DirectMethodDefinitions.insert (std::make_pair (COMD, F));
4076
+ return F;
4077
+ }
4078
+
4079
+ // Objective-C allows for the declaration and implementation types
4080
+ // to differ slightly.
4081
+ //
4082
+ // If we're being asked for the Function associated for a method
4083
+ // implementation, a previous value might have been cached
4084
+ // based on the type of the canonical declaration.
4085
+ //
4086
+ // If these do not match, then we'll replace this function with
4087
+ // a new one that has the proper type below.
4088
+ if (!OMD->getBody () || COMD->getReturnType () == OMD->getReturnType ())
4089
+ return I->second ;
4090
+
4091
+ OldFn = I->second ;
4092
+ Fn = llvm::Function::Create (MethodTy, llvm::GlobalValue::ExternalLinkage, " " ,
4093
+ &CGM.getModule ());
4094
+ Fn->takeName (OldFn);
4095
+ OldFn->replaceAllUsesWith (Fn);
4096
+ OldFn->eraseFromParent ();
4097
+
4098
+ // Replace the cached function in the map.
4099
+ I->second = Fn;
4100
+ return Fn;
3935
4101
}
3936
4102
3937
4103
void CGObjCGNU::GenerateDirectMethodPrologue (CodeGenFunction &CGF,
0 commit comments