diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index a1572578fb14..3784844ef102 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -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) +/// Generate direct method precondition thunks to expose symbols and optimize nil checks. +CODEGENOPT(ObjCDirectPreconditionThunk, 1, 0, Benign) // The optimization options affect frontend options, which in turn do affect the AST. diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 5cae8fb86347..3fc3c19f2658 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -161,6 +161,9 @@ def warn_drv_unsupported_diag_option_for_flang : Warning< def warn_drv_unsupported_option_for_processor : Warning< "ignoring '%0' option as it is not currently supported for processor '%1'">, InGroup; +def warn_drv_unsupported_option_for_runtime : Warning< + "ignoring '%0' option as it is not currently supported for runtime '%1'">, + InGroup; def warn_drv_unsupported_openmp_library : Warning< "the library '%0=%1' is not supported, OpenMP will not be enabled">, InGroup; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 04756ce486ea..dd039fd47426 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3799,6 +3799,11 @@ defm objc_avoid_heapify_local_blocks : BoolFOption<"objc-avoid-heapify-local-blo PosFlag, NegFlag, BothFlags<[], [CC1Option], " to avoid heapifying local blocks">>; +defm objc_direct_precondition_thunk : BoolFOption<"objc-direct-precondition-thunk", + CodeGenOpts<"ObjCDirectPreconditionThunk">, DefaultFalse, + PosFlag, + NegFlag>; defm disable_block_signature_string : BoolFOption<"disable-block-signature-string", CodeGenOpts<"DisableBlockSignatureString">, DefaultFalse, PosFlag, diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index 76e0054f4c9d..3d47dc9560c6 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -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) @@ -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(CGF.CurCodeDecl)) { + if (auto curMethod = dyn_cast_or_null(CGF.CurCodeDecl)) { auto self = curMethod->getSelfDecl(); if (self->getType().isConstQualified()) { if (auto LI = dyn_cast(receiver->stripPointerCasts())) { @@ -466,11 +463,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; } diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h index 72997bf6348a..8cd75b19c4d8 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -117,7 +117,8 @@ public: 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. @@ -322,10 +323,12 @@ public: MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method, QualType resultType, CallArgList &callArgs); + bool canMessageReceiverBeNull(CodeGenFunction &CGF, const ObjCMethodDecl *method, bool isSuper, const ObjCInterfaceDecl *classReceiver, llvm::Value *receiver); + static bool isWeakLinkedClass(const ObjCInterfaceDecl *cls); /// Destroy the callee-destroyed arguments of the given method, diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index e36ad87e67e3..38b052e5cd1d 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -717,6 +717,35 @@ public: /// Return true iff an Objective-C runtime has been configured. bool hasObjCRuntime() { return !!ObjCRuntime; } + /// Check if a direct method should use precondition thunks (exposed symbols). + /// This applies to ALL direct methods (including variadic). + /// Returns false if OMD is null or not a direct method. + /// + /// Also checks the runtime family, currently we only support NeXT. + /// TODO: Add support for GNUStep as well. + bool usePreconditionThunk(const ObjCMethodDecl *OMD) const { + return OMD && OMD->isDirectMethod() && + getLangOpts().ObjCRuntime.allowsDirectDispatch() && + getLangOpts().ObjCRuntime.isNeXTFamily() && + getCodeGenOpts().ObjCDirectPreconditionThunk; + } + + /// Check if a direct method should use precondition thunks at call sites. + /// This applies only to non-variadic direct methods. + /// Returns false if OMD is null or not eligible for thunks (variadic + /// methods). + bool shouldHavePreconditionThunk(const ObjCMethodDecl *OMD) const { + return OMD && usePreconditionThunk(OMD) && !OMD->isVariadic(); + } + + /// Check if a direct method should have inline precondition checks at call + /// sites. This applies to direct methods that cannot use thunks (variadic + /// methods). These methods get exposed symbols but need inline precondition + /// checks instead of thunks. Returns false if OMD is null or not eligible. + bool shouldHavePreconditionInline(const ObjCMethodDecl *OMD) const { + return OMD && usePreconditionThunk(OMD) && OMD->isVariadic(); + } + const std::string &getModuleNameHash() const { return ModuleNameHash; } /// Return a reference to the configured OpenCL runtime. diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 8692200b40a6..a495a433cd15 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4098,6 +4098,19 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D, } } + // Forward -fobjc-direct-precondition-thunk to cc1 + // Defaults to false and needs explict turn on for now + // TODO: switch to default true and needs explict turn off in the future. + // TODO: add support for other runtimes + if (Args.hasFlag(options::OPT_fobjc_direct_precondition_thunk, + options::OPT_fno_objc_direct_precondition_thunk, false)) { + if (Runtime.isNeXTFamily()) { + CmdArgs.push_back("-fobjc-direct-precondition-thunk"); + } else { + D.Diag(diag::warn_drv_unsupported_option_for_runtime) + << "-fobjc-direct-precondition-thunk" << Runtime.getAsString(); + } + } // 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() && diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index e5a23270ea73..5871f1580d6b 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -597,6 +597,23 @@ // CHECK_DISABLE_DIRECT: -fobjc-disable-direct-methods-for-testing // CHECK_NO_DISABLE_DIRECT-NOT: -fobjc-disable-direct-methods-for-testing +// RUN: %clang -### --target=arm64-apple-macos10 -xobjective-c -fobjc-direct-precondition-thunk %s 2>&1 | FileCheck -check-prefix=CHECK_DIRECT_PRECONDITION_THUNK %s +// RUN: %clang -### --target=arm64-apple-macos10 -xobjective-c -fno-objc-direct-precondition-thunk %s 2>&1 | FileCheck -check-prefix=CHECK_NO_DIRECT_PRECONDITION_THUNK %s +// RUN: %clang -### --target=arm64-apple-macos10 -xobjective-c -fobjc-direct-precondition-thunk -fno-objc-direct-precondition-thunk %s 2>&1 | FileCheck -check-prefix=CHECK_NO_DIRECT_PRECONDITION_THUNK %s +// RUN: %clang -### --target=arm64-apple-macos10 -xobjective-c -fno-objc-direct-precondition-thunk -fobjc-direct-precondition-thunk %s 2>&1 | FileCheck -check-prefix=CHECK_DIRECT_PRECONDITION_THUNK %s +// RUN: %clang -### --target=arm64-apple-macos10 -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_NO_DIRECT_PRECONDITION_THUNK %s +// CHECK_DIRECT_PRECONDITION_THUNK: "-fobjc-direct-precondition-thunk" +// CHECK_NO_DIRECT_PRECONDITION_THUNK-NOT: -fobjc-direct-precondition-thunk + +// Test that -fobjc-direct-precondition-thunk emits a warning when used with GNU runtime +// and that the flag is not passed to cc1. +// RUN: %clang --target=x86_64-linux-gnu -fobjc-runtime=gnustep-2.0 -fobjc-direct-precondition-thunk -### -c -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_GNUSTEP_WARN %s +// CHECK_GNUSTEP_WARN: warning: ignoring '-fobjc-direct-precondition-thunk' option as it is not currently supported for runtime 'gnustep-2.0' [-Woption-ignored] +// CHECK_GNUSTEP_WARN-NOT: "-fobjc-direct-precondition-thunk" +// RUN: %clang --target=x86_64-linux-gnu -fobjc-runtime=gcc -fobjc-direct-precondition-thunk -### -c -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_GCC_WARN %s +// CHECK_GCC_WARN: warning: ignoring '-fobjc-direct-precondition-thunk' option as it is not currently supported for runtime 'gcc' [-Woption-ignored] +// CHECK_GCC_WARN-NOT: "-fobjc-direct-precondition-thunk" + // RUN: %clang -### -S -fjmc --target=x86_64-unknown-linux %s 2>&1 | FileCheck -check-prefixes=CHECK_JMC_WARN,CHECK_NOJMC %s // RUN: %clang -### -S -fjmc --target=x86_64-pc-windows-msvc %s 2>&1 | FileCheck -check-prefixes=CHECK_JMC_WARN,CHECK_NOJMC %s // RUN: %clang -### -S -fjmc -g --target=x86_64-pc-windows-msvc %s 2>&1 | FileCheck -check-prefix=CHECK_JMC %s