ObjCRuntime.h 15 KB

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