Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0, Benign) ///< -fno-zero-initialized-in-
ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy, Benign)
/// Replace certain message sends with calls to ObjC runtime entrypoints
CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1, Benign)
CODEGENOPT(ObjCMsgSendSelectorStubs , 1, 0, Benign) ///< Use per-selector linker stubs for objc_msgSend
CODEGENOPT(ObjCMsgSendClassSelectorStubs, 1, 0, Benign) ///< Use per-class, per-selector linker stubs for objc_msgSend
CODEGENOPT(ObjCAvoidHeapifyLocalBlocks, 1, 0, Benign)


Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3824,6 +3824,13 @@ defm objc_convert_messages_to_runtime_calls : BoolFOption<"objc-convert-messages
CodeGenOpts<"ObjCConvertMessagesToRuntimeCalls">, DefaultTrue,
NegFlag<SetFalse, [], [ClangOption, CC1Option]>,
PosFlag<SetTrue>>;
defm objc_msgsend_selector_stubs : BoolFOption<"objc-msgsend-selector-stubs",
CodeGenOpts<"ObjCMsgSendSelectorStubs">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option]>, NegFlag<SetFalse>>;
defm objc_msgsend_class_selector_stubs : BoolFOption<"objc-msgsend-class-selector-stubs",
CodeGenOpts<"ObjCMsgSendClassSelectorStubs">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option]>,
NegFlag<SetFalse>>;
defm objc_arc_exceptions : BoolFOption<"objc-arc-exceptions",
CodeGenOpts<"ObjCAutoRefCountExceptions">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
Expand Down
76 changes: 73 additions & 3 deletions clang/lib/CodeGen/CGObjCMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,10 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
llvm::DenseMap<const ObjCMethodDecl *, llvm::Function *>
DirectMethodDefinitions;

/// MethodSelectorStubs - Map from (selector,class) to stub function.
llvm::DenseMap<std::pair<Selector, StringRef>, llvm::Function *>
MethodSelectorStubs;

/// PropertyNames - uniqued method variable names.
llvm::DenseMap<IdentifierInfo *, llvm::GlobalVariable *> PropertyNames;

Expand Down Expand Up @@ -1061,6 +1065,10 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) override;

llvm::Function *
GenerateMethodSelectorStub(Selector Sel, StringRef ClassName,
const ObjCCommonTypesHelper &ObjCTypes);

void GenerateProtocol(const ObjCProtocolDecl *PD) override;

/// GetOrEmitProtocolRef - Get a forward reference to the protocol
Expand Down Expand Up @@ -2057,12 +2065,14 @@ CodeGen::RValue CGObjCCommonMac::EmitMessageSend(
const ObjCCommonTypesHelper &ObjCTypes) {
CodeGenTypes &Types = CGM.getTypes();
auto selTy = CGF.getContext().getObjCSelType();
llvm::Value *ReceiverValue =
llvm::PoisonValue::get(Types.ConvertType(Arg0Ty));
llvm::Value *SelValue = llvm::UndefValue::get(Types.ConvertType(selTy));

CallArgList ActualArgs;
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
ActualArgs.add(RValue::get(Arg0), Arg0Ty);
ActualArgs.add(RValue::get(ReceiverValue), Arg0Ty);
if (!Method || !Method->isDirectMethod())
ActualArgs.add(RValue::get(SelValue), selTy);
ActualArgs.addFrom(CallArgs);
Expand All @@ -2079,6 +2089,7 @@ CodeGen::RValue CGObjCCommonMac::EmitMessageSend(
canMessageReceiverBeNull(CGF, Method, IsSuper, ClassReceiver, Arg0);

bool RequiresNullCheck = false;
bool RequiresReceiverValue = true;
bool RequiresSelValue = true;

llvm::FunctionCallee Fn = nullptr;
Expand All @@ -2104,8 +2115,32 @@ CodeGen::RValue CGObjCCommonMac::EmitMessageSend(
// must be made for it.
if (ReceiverCanBeNull && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
RequiresNullCheck = true;
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
// The class name that's used to create the class msgSend stub declaration.
StringRef ClassName;

// We cannot use class msgSend stubs in the following cases:
// 1. The class is annotated with `objc_class_stub` or
// `objc_runtime_visible`.
// 2. The selector name contains a '$'.
if (CGM.getCodeGenOpts().ObjCMsgSendClassSelectorStubs && ClassReceiver &&
Method && Method->isClassMethod() &&
!ClassReceiver->hasAttr<ObjCClassStubAttr>() &&
!ClassReceiver->hasAttr<ObjCRuntimeVisibleAttr>() &&
Sel.getAsString().find('$') == std::string::npos)
ClassName = ClassReceiver->getObjCRuntimeNameAsString();

bool UseClassStub = ClassName.data();
// Try to use a selector stub declaration instead of objc_msgSend.
if (!IsSuper &&
(CGM.getCodeGenOpts().ObjCMsgSendSelectorStubs || UseClassStub)) {
Fn = GenerateMethodSelectorStub(Sel, ClassName, ObjCTypes);
// Selector stubs synthesize `_cmd` in the stub, so we don't have to.
RequiresReceiverValue = !UseClassStub;
RequiresSelValue = false;
} else {
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
}
}

// Cast function to proper signature
Expand All @@ -2126,6 +2161,10 @@ CodeGen::RValue CGObjCCommonMac::EmitMessageSend(
nullReturn.init(CGF, Arg0);
}

// Pass the receiver value if it's needed.
if (RequiresReceiverValue)
ActualArgs[0] = CallArg(RValue::get(Arg0), Arg0Ty);

// If a selector value needs to be passed, emit the load before the call.
if (RequiresSelValue) {
SelValue = GetSelector(CGF, Sel);
Expand Down Expand Up @@ -4013,6 +4052,35 @@ void CGObjCCommonMac::GenerateDirectMethodPrologue(
}
}

llvm::Function *CGObjCCommonMac::GenerateMethodSelectorStub(
Selector Sel, StringRef ClassName, const ObjCCommonTypesHelper &ObjCTypes) {
assert((!ClassName.data() || !ClassName.empty()) &&
"class name cannot be an empty string");
auto Key = std::make_pair(Sel, ClassName);
auto I = MethodSelectorStubs.find(Key);

if (I != MethodSelectorStubs.end())
return I->second;

auto *FnTy = llvm::FunctionType::get(
ObjCTypes.ObjectPtrTy, {ObjCTypes.ObjectPtrTy, ObjCTypes.SelectorPtrTy},
/*IsVarArg=*/true);
std::string FnName;

if (ClassName.data())
FnName = ("objc_msgSendClass$" + Sel.getAsString() + "$_OBJC_CLASS_$_" +
llvm::Twine(ClassName))
.str();
else
FnName = "objc_msgSend$" + Sel.getAsString();

auto *Fn =
cast<llvm::Function>(CGM.CreateRuntimeFunction(FnTy, FnName).getCallee());

MethodSelectorStubs.insert(std::make_pair(Key, Fn));
return Fn;
}

llvm::GlobalVariable *
CGObjCCommonMac::CreateMetadataVar(Twine Name, ConstantStructBuilder &Init,
StringRef Section, CharUnits Align,
Expand Down Expand Up @@ -6353,6 +6421,8 @@ llvm::GlobalVariable *CGObjCNonFragileABIMac::BuildClassObject(
if (!CGM.getTriple().isOSBinFormatCOFF())
if (HiddenVisibility)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
if (CGM.getCodeGenOpts().ObjCMsgSendClassSelectorStubs && !isMetaclass)
CGM.addUsedGlobal(GV);
return GV;
}

Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4244,6 +4244,18 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D,
}
}

if (types::isObjC(Input.getType())) {
// Pass down -fobjc-msgsend-selector-stubs if present.
if (Args.hasFlag(options::OPT_fobjc_msgsend_selector_stubs,
options::OPT_fno_objc_msgsend_selector_stubs, false))
CmdArgs.push_back("-fobjc-msgsend-selector-stubs");

// Pass down -fobjc-msgsend-class-selector-stubs if present.
if (Args.hasFlag(options::OPT_fobjc_msgsend_class_selector_stubs,
options::OPT_fno_objc_msgsend_class_selector_stubs, false))
CmdArgs.push_back("-fobjc-msgsend-class-selector-stubs");
}

// When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option
// to do Array/Dictionary subscripting by default.
if (Arch == llvm::Triple::x86 && T.isMacOSX() &&
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3526,6 +3526,23 @@ void Darwin::addClangTargetOptions(
isAlignedAllocationUnavailable())
CC1Args.push_back("-faligned-alloc-unavailable");

// Enable objc_msgSend selector stubs by default if the linker supports it.
// ld64-811.2+ does, for arm64, arm64e, and arm64_32.
if (!DriverArgs.hasArgNoClaim(options::OPT_fobjc_msgsend_selector_stubs,
options::OPT_fno_objc_msgsend_selector_stubs) &&
getTriple().isAArch64() &&
(getLinkerVersion(DriverArgs) >= VersionTuple(811, 2)))
CC1Args.push_back("-fobjc-msgsend-selector-stubs");

// Enable objc_msgSend class selector stubs by default if the linker supports
// it. ld64-1250+ does, for arm64, arm64e, and arm64_32.
if (!DriverArgs.hasArgNoClaim(
options::OPT_fobjc_msgsend_class_selector_stubs,
options::OPT_fno_objc_msgsend_class_selector_stubs) &&
getTriple().isAArch64() &&
(getLinkerVersion(DriverArgs) >= VersionTuple(1250, 0)))
CC1Args.push_back("-fobjc-msgsend-class-selector-stubs");

// Pass "-fno-sized-deallocation" only when the user hasn't manually enabled
// or disabled sized deallocations.
if (!DriverArgs.hasArgNoClaim(options::OPT_fsized_deallocation,
Expand Down
Loading