Skip to content
Draft
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
6 changes: 6 additions & 0 deletions clang/include/clang/AST/DeclObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,12 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
/// True if the method is tagged as objc_direct
bool isDirectMethod() const;

/// Check if this direct method can move nil-check to thunk.
/// Variadic functions cannot use thunks (musttail incompatible with va_arg)
bool canHaveNilCheckThunk() const {
return isDirectMethod() && !isVariadic();
}

/// True if the method has a parameter that's destroyed in the callee.
bool hasParamDestroyedInCallee() const;

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy, Benign)
/// Replace certain message sends with calls to ObjC runtime entrypoints
CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1, Benign)
CODEGENOPT(ObjCAvoidHeapifyLocalBlocks, 1, 0, Benign)
/// Expose objc_direct method symbols publicly and optimize nil checks.
CODEGENOPT(ObjCExposeDirectMethods, 1, 0, Benign)


// The optimization options affect frontend options, which in turn do affect the AST.
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Options/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3775,6 +3775,11 @@ defm objc_avoid_heapify_local_blocks : BoolFOption<"objc-avoid-heapify-local-blo
PosFlag<SetTrue, [], [ClangOption], "Try">,
NegFlag<SetFalse, [], [ClangOption], "Don't try">,
BothFlags<[], [CC1Option], " to avoid heapifying local blocks">>;
defm objc_expose_direct_methods : BoolFOption<"objc-expose-direct-methods",
CodeGenOpts<"ObjCExposeDirectMethods">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Expose direct method symbols and move nil checks to caller-side thunks">,
NegFlag<SetFalse>>;
defm disable_block_signature_string : BoolFOption<"disable-block-signature-string",
CodeGenOpts<"DisableBlockSignatureString">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Disable">,
Expand Down
26 changes: 15 additions & 11 deletions clang/lib/CodeGen/CGObjCRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,11 +382,9 @@ CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method,
return MessageSendInfo(argsInfo, signatureType);
}

bool CGObjCRuntime::canMessageReceiverBeNull(CodeGenFunction &CGF,
const ObjCMethodDecl *method,
bool isSuper,
const ObjCInterfaceDecl *classReceiver,
llvm::Value *receiver) {
bool CGObjCRuntime::canMessageReceiverBeNull(
CodeGenFunction &CGF, const ObjCMethodDecl *method, bool isSuper,
const ObjCInterfaceDecl *classReceiver, llvm::Value *receiver) {
// Super dispatch assumes that self is non-null; even the messenger
// doesn't have a null check internally.
if (isSuper)
Expand All @@ -399,8 +397,7 @@ bool CGObjCRuntime::canMessageReceiverBeNull(CodeGenFunction &CGF,

// If we're emitting a method, and self is const (meaning just ARC, for now),
// and the receiver is a load of self, then self is a valid object.
if (auto curMethod =
dyn_cast_or_null<ObjCMethodDecl>(CGF.CurCodeDecl)) {
if (auto curMethod = dyn_cast_or_null<ObjCMethodDecl>(CGF.CurCodeDecl)) {
auto self = curMethod->getSelfDecl();
if (self->getType().isConstQualified()) {
if (auto LI = dyn_cast<llvm::LoadInst>(receiver->stripPointerCasts())) {
Expand All @@ -416,6 +413,13 @@ bool CGObjCRuntime::canMessageReceiverBeNull(CodeGenFunction &CGF,
return true;
}

bool CGObjCRuntime::canClassObjectBeUnrealized(
const ObjCInterfaceDecl *CalleeClassDecl, CodeGenFunction &CGF) const {
// TODO
// Otherwise, assume it can be unrealized.
return true;
}

bool CGObjCRuntime::isWeakLinkedClass(const ObjCInterfaceDecl *ID) {
do {
if (ID->isWeakImported())
Expand Down Expand Up @@ -466,11 +470,11 @@ clang::CodeGen::emitObjCProtocolObject(CodeGenModule &CGM,
}

std::string CGObjCRuntime::getSymbolNameForMethod(const ObjCMethodDecl *OMD,
bool includeCategoryName) {
bool includeCategoryName,
bool includePrefixByte) {
std::string buffer;
llvm::raw_string_ostream out(buffer);
CGM.getCXXABI().getMangleContext().mangleObjCMethodName(OMD, out,
/*includePrefixByte=*/true,
includeCategoryName);
CGM.getCXXABI().getMangleContext().mangleObjCMethodName(
OMD, out, includePrefixByte, includeCategoryName);
return buffer;
}
15 changes: 14 additions & 1 deletion clang/lib/CodeGen/CGObjCRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ class CGObjCRuntime {
virtual ~CGObjCRuntime();

std::string getSymbolNameForMethod(const ObjCMethodDecl *method,
bool includeCategoryName = true);
bool includeCategoryName = true,
bool includePrefixByte = true);

/// Generate the function required to register all Objective-C components in
/// this compilation unit with the runtime library.
Expand Down Expand Up @@ -322,10 +323,22 @@ class CGObjCRuntime {
MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method,
QualType resultType,
CallArgList &callArgs);

bool canMessageReceiverBeNull(CodeGenFunction &CGF,
const ObjCMethodDecl *method, bool isSuper,
const ObjCInterfaceDecl *classReceiver,
llvm::Value *receiver);

/// Check if a class object can be unrealized (not yet initialized).
/// Returns true if the class may be unrealized, false if provably realized.
///
/// TODO: Returns false if:
/// - An instance method on the same class was called in a dominating path
/// - The class was explicitly realized earlier in control flow
/// - Note: [Parent foo] does NOT realize Child (inheritance care needed)
virtual bool canClassObjectBeUnrealized(const ObjCInterfaceDecl *ClassDecl,
CodeGenFunction &CGF) const;

static bool isWeakLinkedClass(const ObjCInterfaceDecl *cls);

/// Destroy the callee-destroyed arguments of the given method,
Expand Down
26 changes: 26 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,32 @@ class CodeGenModule : public CodeGenTypeCache {
/// Return true iff an Objective-C runtime has been configured.
bool hasObjCRuntime() { return !!ObjCRuntime; }

/// Check if a direct method should have its symbol exposed (no \01 prefix).
/// This applies to ALL direct methods (including variadic).
/// Returns false if OMD is null or not a direct method.
bool shouldExposeSymbol(const ObjCMethodDecl *OMD) const {
return OMD && OMD->isDirectMethod() &&
getLangOpts().ObjCRuntime.isNeXTFamily() &&
getCodeGenOpts().ObjCExposeDirectMethods;
}

/// Check if a direct method should use nil-check thunks at call sites.
/// This applies only to non-variadic direct methods.
/// Variadic methods cannot use thunks (musttail incompatible with va_arg).
/// Returns false if OMD is null or not eligible for thunks.
bool shouldHaveNilCheckThunk(const ObjCMethodDecl *OMD) const {
return OMD && shouldExposeSymbol(OMD) && OMD->canHaveNilCheckThunk();
}

/// Check if a direct method should have inline nil checks at call sites.
/// This applies to direct methods that cannot use thunks (e.g., variadic
/// methods). These methods get exposed symbols but need inline nil checks
/// instead of thunks. Returns false if OMD is null or not eligible for inline
/// nil checks.
bool shouldHaveNilCheckInline(const ObjCMethodDecl *OMD) const {
return OMD && shouldExposeSymbol(OMD) && !OMD->canHaveNilCheckThunk();
}

const std::string &getModuleNameHash() const { return ModuleNameHash; }

/// Return a reference to the configured OpenCL runtime.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4096,6 +4096,10 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D,
}
}

// Forward -fobjc-expose-direct-methods to cc1
if (Args.hasArg(options::OPT_fobjc_expose_direct_methods))
CmdArgs.push_back("-fobjc-expose-direct-methods");

// 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
Loading