Skip to content

Commit b1f9079

Browse files
author
git apple-llvm automerger
committed
Merge commit 'f36845d0c696' from llvm.org/main into next
2 parents 3e1a667 + f36845d commit b1f9079

File tree

3 files changed

+239
-27
lines changed

3 files changed

+239
-27
lines changed

clang/include/clang/Basic/ObjCRuntime.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,13 @@ class ObjCRuntime {
211211
case GCC:
212212
return false;
213213
case GNUstep:
214-
return false;
214+
// This could be enabled for all versions, except for the fact that the
215+
// implementation of `objc_retain` and friends prior to 2.2 call [object
216+
// retain] in their fall-back paths, which leads to infinite recursion if
217+
// the runtime is built with this enabled. Since distributions typically
218+
// build all Objective-C things with the same compiler version and flags,
219+
// it's better to be conservative here.
220+
return (getVersion() >= VersionTuple(2, 2));
215221
case ObjFW:
216222
return false;
217223
}
@@ -248,7 +254,7 @@ class ObjCRuntime {
248254
case GCC:
249255
return false;
250256
case GNUstep:
251-
return false;
257+
return getVersion() >= VersionTuple(2, 2);
252258
case ObjFW:
253259
return false;
254260
}
@@ -266,6 +272,8 @@ class ObjCRuntime {
266272
return getVersion() >= VersionTuple(12, 2);
267273
case WatchOS:
268274
return getVersion() >= VersionTuple(5, 2);
275+
case GNUstep:
276+
return getVersion() >= VersionTuple(2, 2);
269277
default:
270278
return false;
271279
}
@@ -463,7 +471,8 @@ class ObjCRuntime {
463471
case iOS: return true;
464472
case WatchOS: return true;
465473
case GCC: return false;
466-
case GNUstep: return false;
474+
case GNUstep:
475+
return (getVersion() >= VersionTuple(2, 2));
467476
case ObjFW: return false;
468477
}
469478
llvm_unreachable("bad kind");

clang/lib/CodeGen/CGObjCGNU.cpp

Lines changed: 190 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "CGObjCRuntime.h"
1919
#include "CodeGenFunction.h"
2020
#include "CodeGenModule.h"
21+
#include "CodeGenTypes.h"
22+
#include "SanitizerMetadata.h"
2123
#include "clang/AST/ASTContext.h"
2224
#include "clang/AST/Attr.h"
2325
#include "clang/AST/Decl.h"
@@ -597,6 +599,10 @@ class CGObjCGNU : public CGObjCRuntime {
597599

598600
llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
599601
const ObjCContainerDecl *CD) override;
602+
603+
// Map to unify direct method definitions.
604+
llvm::DenseMap<const ObjCMethodDecl *, llvm::Function *>
605+
DirectMethodDefinitions;
600606
void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn,
601607
const ObjCMethodDecl *OMD,
602608
const ObjCContainerDecl *CD) override;
@@ -917,6 +923,14 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
917923
ClassAliasSection,
918924
ConstantStringSection
919925
};
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+
};
920934
static const char *const SectionsBaseNames[8];
921935
static const char *const PECOFFSectionsBaseNames[8];
922936
template<SectionKind K>
@@ -932,6 +946,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
932946
/// structure describing the receiver and the class, and a selector as
933947
/// arguments. Returns the IMP for the corresponding method.
934948
LazyRuntimeFunction MsgLookupSuperFn;
949+
/// Function to ensure that +initialize is sent to a class.
950+
LazyRuntimeFunction SentInitializeFn;
935951
/// A flag indicating if we've emitted at least one protocol.
936952
/// If we haven't, then we need to emit an empty protocol, to ensure that the
937953
/// __start__objc_protocols and __stop__objc_protocols sections exist.
@@ -1719,7 +1735,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
17191735
metaclassFields.addInt(LongTy, 0);
17201736
// unsigned long info;
17211737
// objc_class_flag_meta
1722-
metaclassFields.addInt(LongTy, 1);
1738+
metaclassFields.addInt(LongTy, ClassFlags::ClassFlagMeta);
17231739
// long instance_size;
17241740
// Setting this to zero is consistent with the older ABI, but it might be
17251741
// more sensible to set this to sizeof(struct objc_class)
@@ -1993,6 +2009,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
19932009
CGObjCGNUstep2(CodeGenModule &Mod) : CGObjCGNUstep(Mod, 10, 4, 2) {
19942010
MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
19952011
PtrToObjCSuperTy, SelectorTy);
2012+
SentInitializeFn.init(&CGM, "objc_send_initialize",
2013+
llvm::Type::getVoidTy(VMContext), IdTy);
19962014
// struct objc_property
19972015
// {
19982016
// const char *name;
@@ -2006,6 +2024,106 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
20062024
{ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty });
20072025
}
20082026

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+
}
20092127
};
20102128

20112129
const char *const CGObjCGNUstep2::SectionsBaseNames[8] =
@@ -2650,13 +2768,18 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
26502768
}
26512769
}
26522770

2771+
bool isDirect = Method && Method->isDirectMethod();
2772+
26532773
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
26542774
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+
26602783
Receiver = EnforceType(Builder, Receiver, IdTy);
26612784

26622785
llvm::Metadata *impMD[] = {
@@ -2668,7 +2791,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
26682791

26692792
CallArgList ActualArgs;
26702793
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());
26722796
ActualArgs.addFrom(CallArgs);
26732797

26742798
MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
@@ -2687,7 +2811,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
26872811
// Rather than doing a whole target-specific analysis, we assume it
26882812
// only works for void, integer, and pointer types, and in all
26892813
// 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
26912815
// sidesteps the few outright CC incompatibilities we know about that
26922816
// could otherwise lead to crashes, like when a method is expected to
26932817
// return on the x87 floating point stack or adjust the stack pointer
@@ -2721,8 +2845,9 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
27212845
// FIXME: we probably need a size limit here, but we've
27222846
// never imposed one before
27232847
} 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;
27262851
}
27272852
}
27282853

@@ -2766,10 +2891,14 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
27662891
// Get the IMP to call
27672892
llvm::Value *imp;
27682893

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()) {
27732902
case CodeGenOptions::Legacy:
27742903
imp = LookupIMP(CGF, Receiver, cmd, node, MSI);
27752904
break;
@@ -2792,7 +2921,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
27922921
llvm::FunctionType::get(IdTy, IdTy, true), "objc_msgSend")
27932922
.getCallee();
27942923
}
2795-
}
2924+
}
27962925

27972926
// Reset the receiver in case the lookup modified it
27982927
ActualArgs[0] = CallArg(RValue::get(Receiver), ASTIdTy);
@@ -2803,7 +2932,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
28032932
CGPointerAuthInfo pointerAuth; // TODO
28042933
CGCallee callee(CGCalleeInfo(), imp, pointerAuth);
28052934
RValue msgRet = CGF.EmitCall(MSI.CallInfo, callee, Return, ActualArgs, &call);
2806-
call->setMetadata(msgSendMDKind, node);
2935+
if (!isDirect)
2936+
call->setMetadata(msgSendMDKind, node);
28072937

28082938
if (requiresNilReceiverCheck) {
28092939
llvm::BasicBlock *nonNilPathBB = CGF.Builder.GetInsertBlock();
@@ -3926,14 +4056,50 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
39264056
CodeGenTypes &Types = CGM.getTypes();
39274057
llvm::FunctionType *MethodTy =
39284058
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;
39374103
}
39384104

39394105
void CGObjCGNU::GenerateDirectMethodPrologue(CodeGenFunction &CGF,

0 commit comments

Comments
 (0)