Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:50

0001 //===- ObjCRuntime.h - Objective-C Runtime Configuration --------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 /// \file
0010 /// Defines types useful for describing an Objective-C runtime.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_BASIC_OBJCRUNTIME_H
0015 #define LLVM_CLANG_BASIC_OBJCRUNTIME_H
0016 
0017 #include "clang/Basic/LLVM.h"
0018 #include "llvm/ADT/StringRef.h"
0019 #include "llvm/Support/ErrorHandling.h"
0020 #include "llvm/Support/HashBuilder.h"
0021 #include "llvm/Support/VersionTuple.h"
0022 #include "llvm/TargetParser/Triple.h"
0023 #include <string>
0024 
0025 namespace clang {
0026 
0027 /// The basic abstraction for the target Objective-C runtime.
0028 class ObjCRuntime {
0029 public:
0030   /// The basic Objective-C runtimes that we know about.
0031   enum Kind {
0032     /// 'macosx' is the Apple-provided NeXT-derived runtime on Mac OS
0033     /// X platforms that use the non-fragile ABI; the version is a
0034     /// release of that OS.
0035     MacOSX,
0036 
0037     /// 'macosx-fragile' is the Apple-provided NeXT-derived runtime on
0038     /// Mac OS X platforms that use the fragile ABI; the version is a
0039     /// release of that OS.
0040     FragileMacOSX,
0041 
0042     /// 'ios' is the Apple-provided NeXT-derived runtime on iOS or the iOS
0043     /// simulator;  it is always non-fragile.  The version is a release
0044     /// version of iOS.
0045     iOS,
0046 
0047     /// 'watchos' is a variant of iOS for Apple's watchOS. The version
0048     /// is a release version of watchOS.
0049     WatchOS,
0050 
0051     /// 'gcc' is the Objective-C runtime shipped with GCC, implementing a
0052     /// fragile Objective-C ABI
0053     GCC,
0054 
0055     /// 'gnustep' is the modern non-fragile GNUstep runtime.
0056     GNUstep,
0057 
0058     /// 'objfw' is the Objective-C runtime included in ObjFW
0059     ObjFW
0060   };
0061 
0062 private:
0063   Kind TheKind = MacOSX;
0064   VersionTuple Version;
0065 
0066 public:
0067   /// A bogus initialization of the runtime.
0068   ObjCRuntime() = default;
0069   ObjCRuntime(Kind kind, const VersionTuple &version)
0070       : TheKind(kind), Version(version) {}
0071 
0072   void set(Kind kind, VersionTuple version) {
0073     TheKind = kind;
0074     Version = version;
0075   }
0076 
0077   Kind getKind() const { return TheKind; }
0078   const VersionTuple &getVersion() const { return Version; }
0079 
0080   /// Does this runtime follow the set of implied behaviors for a
0081   /// "non-fragile" ABI?
0082   bool isNonFragile() const {
0083     switch (getKind()) {
0084     case FragileMacOSX: return false;
0085     case GCC: return false;
0086     case MacOSX: return true;
0087     case GNUstep: return true;
0088     case ObjFW: return true;
0089     case iOS: return true;
0090     case WatchOS: return true;
0091     }
0092     llvm_unreachable("bad kind");
0093   }
0094 
0095   /// The inverse of isNonFragile():  does this runtime follow the set of
0096   /// implied behaviors for a "fragile" ABI?
0097   bool isFragile() const { return !isNonFragile(); }
0098 
0099   /// The default dispatch mechanism to use for the specified architecture
0100   bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) {
0101     // The GNUstep runtime uses a newer dispatch method by default from
0102     // version 1.6 onwards
0103     if (getKind() == GNUstep) {
0104       switch (Arch) {
0105       case llvm::Triple::arm:
0106       case llvm::Triple::x86:
0107       case llvm::Triple::x86_64:
0108         return !(getVersion() >= VersionTuple(1, 6));
0109       case llvm::Triple::aarch64:
0110       case llvm::Triple::mips64:
0111         return !(getVersion() >= VersionTuple(1, 9));
0112       case llvm::Triple::riscv64:
0113         return !(getVersion() >= VersionTuple(2, 2));
0114       default:
0115         return true;
0116       }
0117     } else if ((getKind() == MacOSX) && isNonFragile() &&
0118                (getVersion() >= VersionTuple(10, 0)) &&
0119                (getVersion() < VersionTuple(10, 6)))
0120       return Arch != llvm::Triple::x86_64;
0121     // Except for deployment target of 10.5 or less,
0122     // Mac runtimes use legacy dispatch everywhere now.
0123     return true;
0124   }
0125 
0126   /// Is this runtime basically of the GNU family of runtimes?
0127   bool isGNUFamily() const {
0128     switch (getKind()) {
0129     case FragileMacOSX:
0130     case MacOSX:
0131     case iOS:
0132     case WatchOS:
0133       return false;
0134     case GCC:
0135     case GNUstep:
0136     case ObjFW:
0137       return true;
0138     }
0139     llvm_unreachable("bad kind");
0140   }
0141 
0142   /// Is this runtime basically of the NeXT family of runtimes?
0143   bool isNeXTFamily() const {
0144     // For now, this is just the inverse of isGNUFamily(), but that's
0145     // not inherently true.
0146     return !isGNUFamily();
0147   }
0148 
0149   /// Does this runtime allow ARC at all?
0150   bool allowsARC() const {
0151     switch (getKind()) {
0152     case FragileMacOSX:
0153       // No stub library for the fragile runtime.
0154       return getVersion() >= VersionTuple(10, 7);
0155     case MacOSX: return true;
0156     case iOS: return true;
0157     case WatchOS: return true;
0158     case GCC: return false;
0159     case GNUstep: return true;
0160     case ObjFW: return true;
0161     }
0162     llvm_unreachable("bad kind");
0163   }
0164 
0165   /// Does this runtime natively provide the ARC entrypoints?
0166   ///
0167   /// ARC cannot be directly supported on a platform that does not provide
0168   /// these entrypoints, although it may be supportable via a stub
0169   /// library.
0170   bool hasNativeARC() const {
0171     switch (getKind()) {
0172     case FragileMacOSX: return getVersion() >= VersionTuple(10, 7);
0173     case MacOSX: return getVersion() >= VersionTuple(10, 7);
0174     case iOS: return getVersion() >= VersionTuple(5);
0175     case WatchOS: return true;
0176 
0177     case GCC: return false;
0178     case GNUstep: return getVersion() >= VersionTuple(1, 6);
0179     case ObjFW: return true;
0180     }
0181     llvm_unreachable("bad kind");
0182   }
0183 
0184   /// Does this runtime provide ARC entrypoints that are likely to be faster
0185   /// than an ordinary message send of the appropriate selector?
0186   ///
0187   /// The ARC entrypoints are guaranteed to be equivalent to just sending the
0188   /// corresponding message.  If the entrypoint is implemented naively as just a
0189   /// message send, using it is a trade-off: it sacrifices a few cycles of
0190   /// overhead to save a small amount of code.  However, it's possible for
0191   /// runtimes to detect and special-case classes that use "standard"
0192   /// retain/release behavior; if that's dynamically a large proportion of all
0193   /// retained objects, using the entrypoint will also be faster than using a
0194   /// message send.
0195   ///
0196   /// When this method returns true, Clang will turn non-super message sends of
0197   /// certain selectors into calls to the correspond entrypoint:
0198   ///   retain => objc_retain
0199   ///   release => objc_release
0200   ///   autorelease => objc_autorelease
0201   bool shouldUseARCFunctionsForRetainRelease() const {
0202     switch (getKind()) {
0203     case FragileMacOSX:
0204       return false;
0205     case MacOSX:
0206       return getVersion() >= VersionTuple(10, 10);
0207     case iOS:
0208       return getVersion() >= VersionTuple(8);
0209     case WatchOS:
0210       return true;
0211     case GCC:
0212       return false;
0213     case GNUstep:
0214       // This could be enabled for all versions, except for the fact that the
0215       // implementation of `objc_retain` and friends prior to 2.2 call [object
0216       // retain] in their fall-back paths, which leads to infinite recursion if
0217       // the runtime is built with this enabled.  Since distributions typically
0218       // build all Objective-C things with the same compiler version and flags,
0219       // it's better to be conservative here.
0220       return (getVersion() >= VersionTuple(2, 2));
0221     case ObjFW:
0222       return false;
0223     }
0224     llvm_unreachable("bad kind");
0225   }
0226 
0227   /// Does this runtime provide entrypoints that are likely to be faster
0228   /// than an ordinary message send of the "alloc" selector?
0229   ///
0230   /// The "alloc" entrypoint is guaranteed to be equivalent to just sending the
0231   /// corresponding message.  If the entrypoint is implemented naively as just a
0232   /// message send, using it is a trade-off: it sacrifices a few cycles of
0233   /// overhead to save a small amount of code.  However, it's possible for
0234   /// runtimes to detect and special-case classes that use "standard"
0235   /// alloc behavior; if that's dynamically a large proportion of all
0236   /// objects, using the entrypoint will also be faster than using a message
0237   /// send.
0238   ///
0239   /// When this method returns true, Clang will turn non-super message sends of
0240   /// certain selectors into calls to the corresponding entrypoint:
0241   ///   alloc => objc_alloc
0242   ///   allocWithZone:nil => objc_allocWithZone
0243   bool shouldUseRuntimeFunctionsForAlloc() const {
0244     switch (getKind()) {
0245     case FragileMacOSX:
0246       return false;
0247     case MacOSX:
0248       return getVersion() >= VersionTuple(10, 10);
0249     case iOS:
0250       return getVersion() >= VersionTuple(8);
0251     case WatchOS:
0252       return true;
0253 
0254     case GCC:
0255       return false;
0256     case GNUstep:
0257       return getVersion() >= VersionTuple(2, 2);
0258     case ObjFW:
0259       return false;
0260     }
0261     llvm_unreachable("bad kind");
0262   }
0263 
0264   /// Does this runtime provide the objc_alloc_init entrypoint? This can apply
0265   /// the same optimization as objc_alloc, but also sends an -init message,
0266   /// reducing code size on the caller.
0267   bool shouldUseRuntimeFunctionForCombinedAllocInit() const {
0268     switch (getKind()) {
0269     case MacOSX:
0270       return getVersion() >= VersionTuple(10, 14, 4);
0271     case iOS:
0272       return getVersion() >= VersionTuple(12, 2);
0273     case WatchOS:
0274       return getVersion() >= VersionTuple(5, 2);
0275     case GNUstep:
0276       return getVersion() >= VersionTuple(2, 2);
0277     default:
0278       return false;
0279     }
0280   }
0281 
0282   /// Does this runtime supports optimized setter entrypoints?
0283   bool hasOptimizedSetter() const {
0284     switch (getKind()) {
0285       case MacOSX:
0286         return getVersion() >= VersionTuple(10, 8);
0287       case iOS:
0288         return (getVersion() >= VersionTuple(6));
0289       case WatchOS:
0290         return true;
0291       case GNUstep:
0292         return getVersion() >= VersionTuple(1, 7);
0293       default:
0294         return false;
0295     }
0296   }
0297 
0298   /// Does this runtime allow the use of __weak?
0299   bool allowsWeak() const {
0300     return hasNativeWeak();
0301   }
0302 
0303   /// Does this runtime natively provide ARC-compliant 'weak'
0304   /// entrypoints?
0305   bool hasNativeWeak() const {
0306     // Right now, this is always equivalent to whether the runtime
0307     // natively supports ARC decision.
0308     return hasNativeARC();
0309   }
0310 
0311   /// Does this runtime directly support the subscripting methods?
0312   ///
0313   /// This is really a property of the library, not the runtime.
0314   bool hasSubscripting() const {
0315     switch (getKind()) {
0316     case FragileMacOSX: return false;
0317     case MacOSX: return getVersion() >= VersionTuple(10, 11);
0318     case iOS: return getVersion() >= VersionTuple(9);
0319     case WatchOS: return true;
0320 
0321     // This is really a lie, because some implementations and versions
0322     // of the runtime do not support ARC.  Probably -fgnu-runtime
0323     // should imply a "maximal" runtime or something?
0324     case GCC: return true;
0325     case GNUstep: return true;
0326     case ObjFW: return true;
0327     }
0328     llvm_unreachable("bad kind");
0329   }
0330 
0331   /// Does this runtime allow sizeof or alignof on object types?
0332   bool allowsSizeofAlignof() const {
0333     return isFragile();
0334   }
0335 
0336   /// Does this runtime allow pointer arithmetic on objects?
0337   ///
0338   /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
0339   /// yields true) [].
0340   bool allowsPointerArithmetic() const {
0341     switch (getKind()) {
0342     case FragileMacOSX:
0343     case GCC:
0344       return true;
0345     case MacOSX:
0346     case iOS:
0347     case WatchOS:
0348     case GNUstep:
0349     case ObjFW:
0350       return false;
0351     }
0352     llvm_unreachable("bad kind");
0353   }
0354 
0355   /// Is subscripting pointer arithmetic?
0356   bool isSubscriptPointerArithmetic() const {
0357     return allowsPointerArithmetic();
0358   }
0359 
0360   /// Does this runtime provide an objc_terminate function?
0361   ///
0362   /// This is used in handlers for exceptions during the unwind process;
0363   /// without it, abort() must be used in pure ObjC files.
0364   bool hasTerminate() const {
0365     switch (getKind()) {
0366     case FragileMacOSX: return getVersion() >= VersionTuple(10, 8);
0367     case MacOSX: return getVersion() >= VersionTuple(10, 8);
0368     case iOS: return getVersion() >= VersionTuple(5);
0369     case WatchOS: return true;
0370     case GCC: return false;
0371     case GNUstep: return false;
0372     case ObjFW: return false;
0373     }
0374     llvm_unreachable("bad kind");
0375   }
0376 
0377   /// Does this runtime support weakly importing classes?
0378   bool hasWeakClassImport() const {
0379     switch (getKind()) {
0380     case MacOSX: return true;
0381     case iOS: return true;
0382     case WatchOS: return true;
0383     case FragileMacOSX: return false;
0384     case GCC: return true;
0385     case GNUstep: return true;
0386     case ObjFW: return true;
0387     }
0388     llvm_unreachable("bad kind");
0389   }
0390 
0391   /// Does this runtime use zero-cost exceptions?
0392   bool hasUnwindExceptions() const {
0393     switch (getKind()) {
0394     case MacOSX: return true;
0395     case iOS: return true;
0396     case WatchOS: return true;
0397     case FragileMacOSX: return false;
0398     case GCC: return true;
0399     case GNUstep: return true;
0400     case ObjFW: return true;
0401     }
0402     llvm_unreachable("bad kind");
0403   }
0404 
0405   bool hasAtomicCopyHelper() const {
0406     switch (getKind()) {
0407     case FragileMacOSX:
0408     case MacOSX:
0409     case iOS:
0410     case WatchOS:
0411       return true;
0412     case GNUstep:
0413       return getVersion() >= VersionTuple(1, 7);
0414     default: return false;
0415     }
0416   }
0417 
0418   /// Is objc_unsafeClaimAutoreleasedReturnValue available?
0419   bool hasARCUnsafeClaimAutoreleasedReturnValue() const {
0420     switch (getKind()) {
0421     case MacOSX:
0422     case FragileMacOSX:
0423       return getVersion() >= VersionTuple(10, 11);
0424     case iOS:
0425       return getVersion() >= VersionTuple(9);
0426     case WatchOS:
0427       return getVersion() >= VersionTuple(2);
0428     case GNUstep:
0429       return false;
0430     default:
0431       return false;
0432     }
0433   }
0434 
0435   /// Are the empty collection symbols available?
0436   bool hasEmptyCollections() const {
0437     switch (getKind()) {
0438     default:
0439       return false;
0440     case MacOSX:
0441       return getVersion() >= VersionTuple(10, 11);
0442     case iOS:
0443       return getVersion() >= VersionTuple(9);
0444     case WatchOS:
0445       return getVersion() >= VersionTuple(2);
0446     }
0447   }
0448 
0449   /// Returns true if this Objective-C runtime supports Objective-C class
0450   /// stubs.
0451   bool allowsClassStubs() const {
0452     switch (getKind()) {
0453     case FragileMacOSX:
0454     case GCC:
0455     case GNUstep:
0456     case ObjFW:
0457       return false;
0458     case MacOSX:
0459     case iOS:
0460     case WatchOS:
0461       return true;
0462     }
0463     llvm_unreachable("bad kind");
0464   }
0465 
0466   /// Does this runtime supports direct dispatch
0467   bool allowsDirectDispatch() const {
0468     switch (getKind()) {
0469     case FragileMacOSX: return false;
0470     case MacOSX: return true;
0471     case iOS: return true;
0472     case WatchOS: return true;
0473     case GCC: return false;
0474     case GNUstep:
0475       return (getVersion() >= VersionTuple(2, 2));
0476     case ObjFW: return false;
0477     }
0478     llvm_unreachable("bad kind");
0479   }
0480 
0481   /// Try to parse an Objective-C runtime specification from the given
0482   /// string.
0483   ///
0484   /// \return true on error.
0485   bool tryParse(StringRef input);
0486 
0487   std::string getAsString() const;
0488 
0489   friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
0490     return left.getKind() == right.getKind() &&
0491            left.getVersion() == right.getVersion();
0492   }
0493 
0494   friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
0495     return !(left == right);
0496   }
0497 
0498   friend llvm::hash_code hash_value(const ObjCRuntime &OCR) {
0499     return llvm::hash_combine(OCR.getKind(), OCR.getVersion());
0500   }
0501 
0502   template <typename HasherT, llvm::endianness Endianness>
0503   friend void addHash(llvm::HashBuilder<HasherT, Endianness> &HBuilder,
0504                       const ObjCRuntime &OCR) {
0505     HBuilder.add(OCR.getKind(), OCR.getVersion());
0506   }
0507 };
0508 
0509 raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
0510 
0511 } // namespace clang
0512 
0513 #endif // LLVM_CLANG_BASIC_OBJCRUNTIME_H