Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===- ObjCRuntime.h - Objective-C Runtime Configuration --------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. /// \file
  10. /// Defines types useful for describing an Objective-C runtime.
  11. //
  12. //===----------------------------------------------------------------------===//
  13.  
  14. #ifndef LLVM_CLANG_BASIC_OBJCRUNTIME_H
  15. #define LLVM_CLANG_BASIC_OBJCRUNTIME_H
  16.  
  17. #include "clang/Basic/LLVM.h"
  18. #include "llvm/ADT/StringRef.h"
  19. #include "llvm/ADT/Triple.h"
  20. #include "llvm/Support/ErrorHandling.h"
  21. #include "llvm/Support/HashBuilder.h"
  22. #include "llvm/Support/VersionTuple.h"
  23. #include <string>
  24.  
  25. namespace clang {
  26.  
  27. /// The basic abstraction for the target Objective-C runtime.
  28. class ObjCRuntime {
  29. public:
  30.   /// The basic Objective-C runtimes that we know about.
  31.   enum Kind {
  32.     /// 'macosx' is the Apple-provided NeXT-derived runtime on Mac OS
  33.     /// X platforms that use the non-fragile ABI; the version is a
  34.     /// release of that OS.
  35.     MacOSX,
  36.  
  37.     /// 'macosx-fragile' is the Apple-provided NeXT-derived runtime on
  38.     /// Mac OS X platforms that use the fragile ABI; the version is a
  39.     /// release of that OS.
  40.     FragileMacOSX,
  41.  
  42.     /// 'ios' is the Apple-provided NeXT-derived runtime on iOS or the iOS
  43.     /// simulator;  it is always non-fragile.  The version is a release
  44.     /// version of iOS.
  45.     iOS,
  46.  
  47.     /// 'watchos' is a variant of iOS for Apple's watchOS. The version
  48.     /// is a release version of watchOS.
  49.     WatchOS,
  50.  
  51.     /// 'gcc' is the Objective-C runtime shipped with GCC, implementing a
  52.     /// fragile Objective-C ABI
  53.     GCC,
  54.  
  55.     /// 'gnustep' is the modern non-fragile GNUstep runtime.
  56.     GNUstep,
  57.  
  58.     /// 'objfw' is the Objective-C runtime included in ObjFW
  59.     ObjFW
  60.   };
  61.  
  62. private:
  63.   Kind TheKind = MacOSX;
  64.   VersionTuple Version;
  65.  
  66. public:
  67.   /// A bogus initialization of the runtime.
  68.   ObjCRuntime() = default;
  69.   ObjCRuntime(Kind kind, const VersionTuple &version)
  70.       : TheKind(kind), Version(version) {}
  71.  
  72.   void set(Kind kind, VersionTuple version) {
  73.     TheKind = kind;
  74.     Version = version;
  75.   }
  76.  
  77.   Kind getKind() const { return TheKind; }
  78.   const VersionTuple &getVersion() const { return Version; }
  79.  
  80.   /// Does this runtime follow the set of implied behaviors for a
  81.   /// "non-fragile" ABI?
  82.   bool isNonFragile() const {
  83.     switch (getKind()) {
  84.     case FragileMacOSX: return false;
  85.     case GCC: return false;
  86.     case MacOSX: return true;
  87.     case GNUstep: return true;
  88.     case ObjFW: return true;
  89.     case iOS: return true;
  90.     case WatchOS: return true;
  91.     }
  92.     llvm_unreachable("bad kind");
  93.   }
  94.  
  95.   /// The inverse of isNonFragile():  does this runtime follow the set of
  96.   /// implied behaviors for a "fragile" ABI?
  97.   bool isFragile() const { return !isNonFragile(); }
  98.  
  99.   /// The default dispatch mechanism to use for the specified architecture
  100.   bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) {
  101.     // The GNUstep runtime uses a newer dispatch method by default from
  102.     // version 1.6 onwards
  103.     if (getKind() == GNUstep && getVersion() >= VersionTuple(1, 6)) {
  104.       if (Arch == llvm::Triple::arm ||
  105.           Arch == llvm::Triple::x86 ||
  106.           Arch == llvm::Triple::x86_64)
  107.         return false;
  108.     }
  109.     else if ((getKind() ==  MacOSX) && isNonFragile() &&
  110.              (getVersion() >= VersionTuple(10, 0)) &&
  111.              (getVersion() < VersionTuple(10, 6)))
  112.         return Arch != llvm::Triple::x86_64;
  113.     // Except for deployment target of 10.5 or less,
  114.     // Mac runtimes use legacy dispatch everywhere now.
  115.     return true;
  116.   }
  117.  
  118.   /// Is this runtime basically of the GNU family of runtimes?
  119.   bool isGNUFamily() const {
  120.     switch (getKind()) {
  121.     case FragileMacOSX:
  122.     case MacOSX:
  123.     case iOS:
  124.     case WatchOS:
  125.       return false;
  126.     case GCC:
  127.     case GNUstep:
  128.     case ObjFW:
  129.       return true;
  130.     }
  131.     llvm_unreachable("bad kind");
  132.   }
  133.  
  134.   /// Is this runtime basically of the NeXT family of runtimes?
  135.   bool isNeXTFamily() const {
  136.     // For now, this is just the inverse of isGNUFamily(), but that's
  137.     // not inherently true.
  138.     return !isGNUFamily();
  139.   }
  140.  
  141.   /// Does this runtime allow ARC at all?
  142.   bool allowsARC() const {
  143.     switch (getKind()) {
  144.     case FragileMacOSX:
  145.       // No stub library for the fragile runtime.
  146.       return getVersion() >= VersionTuple(10, 7);
  147.     case MacOSX: return true;
  148.     case iOS: return true;
  149.     case WatchOS: return true;
  150.     case GCC: return false;
  151.     case GNUstep: return true;
  152.     case ObjFW: return true;
  153.     }
  154.     llvm_unreachable("bad kind");
  155.   }
  156.  
  157.   /// Does this runtime natively provide the ARC entrypoints?
  158.   ///
  159.   /// ARC cannot be directly supported on a platform that does not provide
  160.   /// these entrypoints, although it may be supportable via a stub
  161.   /// library.
  162.   bool hasNativeARC() const {
  163.     switch (getKind()) {
  164.     case FragileMacOSX: return getVersion() >= VersionTuple(10, 7);
  165.     case MacOSX: return getVersion() >= VersionTuple(10, 7);
  166.     case iOS: return getVersion() >= VersionTuple(5);
  167.     case WatchOS: return true;
  168.  
  169.     case GCC: return false;
  170.     case GNUstep: return getVersion() >= VersionTuple(1, 6);
  171.     case ObjFW: return true;
  172.     }
  173.     llvm_unreachable("bad kind");
  174.   }
  175.  
  176.   /// Does this runtime provide ARC entrypoints that are likely to be faster
  177.   /// than an ordinary message send of the appropriate selector?
  178.   ///
  179.   /// The ARC entrypoints are guaranteed to be equivalent to just sending the
  180.   /// corresponding message.  If the entrypoint is implemented naively as just a
  181.   /// message send, using it is a trade-off: it sacrifices a few cycles of
  182.   /// overhead to save a small amount of code.  However, it's possible for
  183.   /// runtimes to detect and special-case classes that use "standard"
  184.   /// retain/release behavior; if that's dynamically a large proportion of all
  185.   /// retained objects, using the entrypoint will also be faster than using a
  186.   /// message send.
  187.   ///
  188.   /// When this method returns true, Clang will turn non-super message sends of
  189.   /// certain selectors into calls to the correspond entrypoint:
  190.   ///   retain => objc_retain
  191.   ///   release => objc_release
  192.   ///   autorelease => objc_autorelease
  193.   bool shouldUseARCFunctionsForRetainRelease() const {
  194.     switch (getKind()) {
  195.     case FragileMacOSX:
  196.       return false;
  197.     case MacOSX:
  198.       return getVersion() >= VersionTuple(10, 10);
  199.     case iOS:
  200.       return getVersion() >= VersionTuple(8);
  201.     case WatchOS:
  202.       return true;
  203.     case GCC:
  204.       return false;
  205.     case GNUstep:
  206.       return false;
  207.     case ObjFW:
  208.       return false;
  209.     }
  210.     llvm_unreachable("bad kind");
  211.   }
  212.  
  213.   /// Does this runtime provide entrypoints that are likely to be faster
  214.   /// than an ordinary message send of the "alloc" selector?
  215.   ///
  216.   /// The "alloc" entrypoint is guaranteed to be equivalent to just sending the
  217.   /// corresponding message.  If the entrypoint is implemented naively as just a
  218.   /// message send, using it is a trade-off: it sacrifices a few cycles of
  219.   /// overhead to save a small amount of code.  However, it's possible for
  220.   /// runtimes to detect and special-case classes that use "standard"
  221.   /// alloc behavior; if that's dynamically a large proportion of all
  222.   /// objects, using the entrypoint will also be faster than using a message
  223.   /// send.
  224.   ///
  225.   /// When this method returns true, Clang will turn non-super message sends of
  226.   /// certain selectors into calls to the corresponding entrypoint:
  227.   ///   alloc => objc_alloc
  228.   ///   allocWithZone:nil => objc_allocWithZone
  229.   bool shouldUseRuntimeFunctionsForAlloc() const {
  230.     switch (getKind()) {
  231.     case FragileMacOSX:
  232.       return false;
  233.     case MacOSX:
  234.       return getVersion() >= VersionTuple(10, 10);
  235.     case iOS:
  236.       return getVersion() >= VersionTuple(8);
  237.     case WatchOS:
  238.       return true;
  239.  
  240.     case GCC:
  241.       return false;
  242.     case GNUstep:
  243.       return false;
  244.     case ObjFW:
  245.       return false;
  246.     }
  247.     llvm_unreachable("bad kind");
  248.   }
  249.  
  250.   /// Does this runtime provide the objc_alloc_init entrypoint? This can apply
  251.   /// the same optimization as objc_alloc, but also sends an -init message,
  252.   /// reducing code size on the caller.
  253.   bool shouldUseRuntimeFunctionForCombinedAllocInit() const {
  254.     switch (getKind()) {
  255.     case MacOSX:
  256.       return getVersion() >= VersionTuple(10, 14, 4);
  257.     case iOS:
  258.       return getVersion() >= VersionTuple(12, 2);
  259.     case WatchOS:
  260.       return getVersion() >= VersionTuple(5, 2);
  261.     default:
  262.       return false;
  263.     }
  264.   }
  265.  
  266.   /// Does this runtime supports optimized setter entrypoints?
  267.   bool hasOptimizedSetter() const {
  268.     switch (getKind()) {
  269.       case MacOSX:
  270.         return getVersion() >= VersionTuple(10, 8);
  271.       case iOS:
  272.         return (getVersion() >= VersionTuple(6));
  273.       case WatchOS:
  274.         return true;
  275.       case GNUstep:
  276.         return getVersion() >= VersionTuple(1, 7);
  277.       default:
  278.         return false;
  279.     }
  280.   }
  281.  
  282.   /// Does this runtime allow the use of __weak?
  283.   bool allowsWeak() const {
  284.     return hasNativeWeak();
  285.   }
  286.  
  287.   /// Does this runtime natively provide ARC-compliant 'weak'
  288.   /// entrypoints?
  289.   bool hasNativeWeak() const {
  290.     // Right now, this is always equivalent to whether the runtime
  291.     // natively supports ARC decision.
  292.     return hasNativeARC();
  293.   }
  294.  
  295.   /// Does this runtime directly support the subscripting methods?
  296.   ///
  297.   /// This is really a property of the library, not the runtime.
  298.   bool hasSubscripting() const {
  299.     switch (getKind()) {
  300.     case FragileMacOSX: return false;
  301.     case MacOSX: return getVersion() >= VersionTuple(10, 11);
  302.     case iOS: return getVersion() >= VersionTuple(9);
  303.     case WatchOS: return true;
  304.  
  305.     // This is really a lie, because some implementations and versions
  306.     // of the runtime do not support ARC.  Probably -fgnu-runtime
  307.     // should imply a "maximal" runtime or something?
  308.     case GCC: return true;
  309.     case GNUstep: return true;
  310.     case ObjFW: return true;
  311.     }
  312.     llvm_unreachable("bad kind");
  313.   }
  314.  
  315.   /// Does this runtime allow sizeof or alignof on object types?
  316.   bool allowsSizeofAlignof() const {
  317.     return isFragile();
  318.   }
  319.  
  320.   /// Does this runtime allow pointer arithmetic on objects?
  321.   ///
  322.   /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
  323.   /// yields true) [].
  324.   bool allowsPointerArithmetic() const {
  325.     switch (getKind()) {
  326.     case FragileMacOSX:
  327.     case GCC:
  328.       return true;
  329.     case MacOSX:
  330.     case iOS:
  331.     case WatchOS:
  332.     case GNUstep:
  333.     case ObjFW:
  334.       return false;
  335.     }
  336.     llvm_unreachable("bad kind");
  337.   }
  338.  
  339.   /// Is subscripting pointer arithmetic?
  340.   bool isSubscriptPointerArithmetic() const {
  341.     return allowsPointerArithmetic();
  342.   }
  343.  
  344.   /// Does this runtime provide an objc_terminate function?
  345.   ///
  346.   /// This is used in handlers for exceptions during the unwind process;
  347.   /// without it, abort() must be used in pure ObjC files.
  348.   bool hasTerminate() const {
  349.     switch (getKind()) {
  350.     case FragileMacOSX: return getVersion() >= VersionTuple(10, 8);
  351.     case MacOSX: return getVersion() >= VersionTuple(10, 8);
  352.     case iOS: return getVersion() >= VersionTuple(5);
  353.     case WatchOS: return true;
  354.     case GCC: return false;
  355.     case GNUstep: return false;
  356.     case ObjFW: return false;
  357.     }
  358.     llvm_unreachable("bad kind");
  359.   }
  360.  
  361.   /// Does this runtime support weakly importing classes?
  362.   bool hasWeakClassImport() const {
  363.     switch (getKind()) {
  364.     case MacOSX: return true;
  365.     case iOS: return true;
  366.     case WatchOS: return true;
  367.     case FragileMacOSX: return false;
  368.     case GCC: return true;
  369.     case GNUstep: return true;
  370.     case ObjFW: return true;
  371.     }
  372.     llvm_unreachable("bad kind");
  373.   }
  374.  
  375.   /// Does this runtime use zero-cost exceptions?
  376.   bool hasUnwindExceptions() const {
  377.     switch (getKind()) {
  378.     case MacOSX: return true;
  379.     case iOS: return true;
  380.     case WatchOS: return true;
  381.     case FragileMacOSX: return false;
  382.     case GCC: return true;
  383.     case GNUstep: return true;
  384.     case ObjFW: return true;
  385.     }
  386.     llvm_unreachable("bad kind");
  387.   }
  388.  
  389.   bool hasAtomicCopyHelper() const {
  390.     switch (getKind()) {
  391.     case FragileMacOSX:
  392.     case MacOSX:
  393.     case iOS:
  394.     case WatchOS:
  395.       return true;
  396.     case GNUstep:
  397.       return getVersion() >= VersionTuple(1, 7);
  398.     default: return false;
  399.     }
  400.   }
  401.  
  402.   /// Is objc_unsafeClaimAutoreleasedReturnValue available?
  403.   bool hasARCUnsafeClaimAutoreleasedReturnValue() const {
  404.     switch (getKind()) {
  405.     case MacOSX:
  406.     case FragileMacOSX:
  407.       return getVersion() >= VersionTuple(10, 11);
  408.     case iOS:
  409.       return getVersion() >= VersionTuple(9);
  410.     case WatchOS:
  411.       return getVersion() >= VersionTuple(2);
  412.     case GNUstep:
  413.       return false;
  414.     default:
  415.       return false;
  416.     }
  417.   }
  418.  
  419.   /// Are the empty collection symbols available?
  420.   bool hasEmptyCollections() const {
  421.     switch (getKind()) {
  422.     default:
  423.       return false;
  424.     case MacOSX:
  425.       return getVersion() >= VersionTuple(10, 11);
  426.     case iOS:
  427.       return getVersion() >= VersionTuple(9);
  428.     case WatchOS:
  429.       return getVersion() >= VersionTuple(2);
  430.     }
  431.   }
  432.  
  433.   /// Returns true if this Objective-C runtime supports Objective-C class
  434.   /// stubs.
  435.   bool allowsClassStubs() const {
  436.     switch (getKind()) {
  437.     case FragileMacOSX:
  438.     case GCC:
  439.     case GNUstep:
  440.     case ObjFW:
  441.       return false;
  442.     case MacOSX:
  443.     case iOS:
  444.     case WatchOS:
  445.       return true;
  446.     }
  447.     llvm_unreachable("bad kind");
  448.   }
  449.  
  450.   /// Does this runtime supports direct dispatch
  451.   bool allowsDirectDispatch() const {
  452.     switch (getKind()) {
  453.     case FragileMacOSX: return false;
  454.     case MacOSX: return true;
  455.     case iOS: return true;
  456.     case WatchOS: return true;
  457.     case GCC: return false;
  458.     case GNUstep: return false;
  459.     case ObjFW: return false;
  460.     }
  461.     llvm_unreachable("bad kind");
  462.   }
  463.  
  464.   /// Try to parse an Objective-C runtime specification from the given
  465.   /// string.
  466.   ///
  467.   /// \return true on error.
  468.   bool tryParse(StringRef input);
  469.  
  470.   std::string getAsString() const;
  471.  
  472.   friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
  473.     return left.getKind() == right.getKind() &&
  474.            left.getVersion() == right.getVersion();
  475.   }
  476.  
  477.   friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
  478.     return !(left == right);
  479.   }
  480.  
  481.   friend llvm::hash_code hash_value(const ObjCRuntime &OCR) {
  482.     return llvm::hash_combine(OCR.getKind(), OCR.getVersion());
  483.   }
  484.  
  485.   template <typename HasherT, llvm::support::endianness Endianness>
  486.   friend void addHash(llvm::HashBuilderImpl<HasherT, Endianness> &HBuilder,
  487.                       const ObjCRuntime &OCR) {
  488.     HBuilder.add(OCR.getKind(), OCR.getVersion());
  489.   }
  490. };
  491.  
  492. raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
  493.  
  494. } // namespace clang
  495.  
  496. #endif // LLVM_CLANG_BASIC_OBJCRUNTIME_H
  497.