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 ] =
@@ -2650,13 +2768,18 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2650
2768
}
2651
2769
}
2652
2770
2771
+ bool isDirect = Method && Method->isDirectMethod ();
2772
+
2653
2773
IdTy = cast<llvm::PointerType>(CGM.getTypes ().ConvertType (ASTIdTy));
2654
2774
llvm::Value *cmd;
2655
- if (Method)
2656
- cmd = GetSelector (CGF, Method);
2657
- else
2658
- cmd = GetSelector (CGF, Sel);
2659
- cmd = EnforceType (Builder, cmd, SelectorTy);
2775
+ if (!isDirect) {
2776
+ if (Method)
2777
+ cmd = GetSelector (CGF, Method);
2778
+ else
2779
+ cmd = GetSelector (CGF, Sel);
2780
+ cmd = EnforceType (Builder, cmd, SelectorTy);
2781
+ }
2782
+
2660
2783
Receiver = EnforceType (Builder, Receiver, IdTy);
2661
2784
2662
2785
llvm::Metadata *impMD[] = {
@@ -2668,7 +2791,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2668
2791
2669
2792
CallArgList ActualArgs;
2670
2793
ActualArgs.add (RValue::get (Receiver), ASTIdTy);
2671
- ActualArgs.add (RValue::get (cmd), CGF.getContext ().getObjCSelType ());
2794
+ if (!isDirect)
2795
+ ActualArgs.add (RValue::get (cmd), CGF.getContext ().getObjCSelType ());
2672
2796
ActualArgs.addFrom (CallArgs);
2673
2797
2674
2798
MessageSendInfo MSI = getMessageSendInfo (Method, ResultType, ActualArgs);
@@ -2687,7 +2811,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2687
2811
// Rather than doing a whole target-specific analysis, we assume it
2688
2812
// only works for void, integer, and pointer types, and in all
2689
2813
// other cases we do an explicit nil check is emitted code. In
2690
- // addition to ensuring we produe a zero value for other types, this
2814
+ // addition to ensuring we produce a zero value for other types, this
2691
2815
// sidesteps the few outright CC incompatibilities we know about that
2692
2816
// could otherwise lead to crashes, like when a method is expected to
2693
2817
// return on the x87 floating point stack or adjust the stack pointer
@@ -2721,8 +2845,9 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2721
2845
// FIXME: we probably need a size limit here, but we've
2722
2846
// never imposed one before
2723
2847
} else {
2724
- // Otherwise, use an explicit check just to be sure.
2725
- requiresExplicitZeroResult = true ;
2848
+ // Otherwise, use an explicit check just to be sure, unless we're
2849
+ // calling a direct method, where the implementation does this for us.
2850
+ requiresExplicitZeroResult = !isDirect;
2726
2851
}
2727
2852
}
2728
2853
@@ -2766,10 +2891,14 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2766
2891
// Get the IMP to call
2767
2892
llvm::Value *imp;
2768
2893
2769
- // If we have non-legacy dispatch specified, we try using the objc_msgSend()
2770
- // functions. These are not supported on all platforms (or all runtimes on a
2771
- // given platform), so we
2772
- switch (CGM.getCodeGenOpts ().getObjCDispatchMethod ()) {
2894
+ // If this is a direct method, just emit it here.
2895
+ if (isDirect)
2896
+ imp = GenerateMethod (Method, Method->getClassInterface ());
2897
+ else
2898
+ // If we have non-legacy dispatch specified, we try using the
2899
+ // objc_msgSend() functions. These are not supported on all platforms
2900
+ // (or all runtimes on a given platform), so we
2901
+ switch (CGM.getCodeGenOpts ().getObjCDispatchMethod ()) {
2773
2902
case CodeGenOptions::Legacy:
2774
2903
imp = LookupIMP (CGF, Receiver, cmd, node, MSI);
2775
2904
break ;
@@ -2792,7 +2921,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2792
2921
llvm::FunctionType::get (IdTy, IdTy, true ), " objc_msgSend" )
2793
2922
.getCallee ();
2794
2923
}
2795
- }
2924
+ }
2796
2925
2797
2926
// Reset the receiver in case the lookup modified it
2798
2927
ActualArgs[0 ] = CallArg (RValue::get (Receiver), ASTIdTy);
@@ -2803,7 +2932,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2803
2932
CGPointerAuthInfo pointerAuth; // TODO
2804
2933
CGCallee callee (CGCalleeInfo (), imp, pointerAuth);
2805
2934
RValue msgRet = CGF.EmitCall (MSI.CallInfo , callee, Return, ActualArgs, &call);
2806
- call->setMetadata (msgSendMDKind, node);
2935
+ if (!isDirect)
2936
+ call->setMetadata (msgSendMDKind, node);
2807
2937
2808
2938
if (requiresNilReceiverCheck) {
2809
2939
llvm::BasicBlock *nonNilPathBB = CGF.Builder .GetInsertBlock ();
@@ -3926,14 +4056,50 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
3926
4056
CodeGenTypes &Types = CGM.getTypes ();
3927
4057
llvm::FunctionType *MethodTy =
3928
4058
Types.GetFunctionType (Types.arrangeObjCMethodDeclaration (OMD));
3929
- std::string FunctionName = getSymbolNameForMethod (OMD);
3930
-
3931
- llvm::Function *Method
3932
- = llvm::Function::Create (MethodTy,
3933
- llvm::GlobalValue::InternalLinkage,
3934
- FunctionName,
3935
- &TheModule);
3936
- return Method;
4059
+
4060
+ bool isDirect = OMD->isDirectMethod ();
4061
+ std::string FunctionName =
4062
+ getSymbolNameForMethod (OMD, /* include category*/ !isDirect);
4063
+
4064
+ if (!isDirect)
4065
+ return llvm::Function::Create (MethodTy,
4066
+ llvm::GlobalVariable::InternalLinkage,
4067
+ FunctionName, &TheModule);
4068
+
4069
+ auto *COMD = OMD->getCanonicalDecl ();
4070
+ auto I = DirectMethodDefinitions.find (COMD);
4071
+ llvm::Function *OldFn = nullptr , *Fn = nullptr ;
4072
+
4073
+ if (I == DirectMethodDefinitions.end ()) {
4074
+ auto *F =
4075
+ llvm::Function::Create (MethodTy, llvm::GlobalVariable::ExternalLinkage,
4076
+ FunctionName, &TheModule);
4077
+ DirectMethodDefinitions.insert (std::make_pair (COMD, F));
4078
+ return F;
4079
+ }
4080
+
4081
+ // Objective-C allows for the declaration and implementation types
4082
+ // to differ slightly.
4083
+ //
4084
+ // If we're being asked for the Function associated for a method
4085
+ // implementation, a previous value might have been cached
4086
+ // based on the type of the canonical declaration.
4087
+ //
4088
+ // If these do not match, then we'll replace this function with
4089
+ // a new one that has the proper type below.
4090
+ if (!OMD->getBody () || COMD->getReturnType () == OMD->getReturnType ())
4091
+ return I->second ;
4092
+
4093
+ OldFn = I->second ;
4094
+ Fn = llvm::Function::Create (MethodTy, llvm::GlobalValue::ExternalLinkage, " " ,
4095
+ &CGM.getModule ());
4096
+ Fn->takeName (OldFn);
4097
+ OldFn->replaceAllUsesWith (Fn);
4098
+ OldFn->eraseFromParent ();
4099
+
4100
+ // Replace the cached function in the map.
4101
+ I->second = Fn;
4102
+ return Fn;
3937
4103
}
3938
4104
3939
4105
void CGObjCGNU::GenerateDirectMethodPrologue (CodeGenFunction &CGF,
0 commit comments