clang 23.0.0git
ObjCRuntime.h
Go to the documentation of this file.
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/Support/ErrorHandling.h"
20#include "llvm/Support/HashBuilder.h"
21#include "llvm/Support/VersionTuple.h"
22#include "llvm/TargetParser/Triple.h"
23#include <string>
24
25namespace clang {
26
27/// The basic abstraction for the target Objective-C runtime.
29public:
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.
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.
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.
46
47 /// 'watchos' is a variant of iOS for Apple's watchOS. The version
48 /// is a release version of watchOS.
50
51 /// 'gcc' is the Objective-C runtime shipped with GCC, implementing a
52 /// fragile Objective-C ABI
54
55 /// 'gnustep' is the modern non-fragile GNUstep runtime.
57
58 /// 'objfw' is the Objective-C runtime included in ObjFW
60 };
61
62private:
63 Kind TheKind = MacOSX;
64 VersionTuple Version;
65
66public:
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) {
104 switch (Arch) {
105 case llvm::Triple::arm:
106 case llvm::Triple::x86:
107 case llvm::Triple::x86_64:
108 return !(getVersion() >= VersionTuple(1, 6));
109 case llvm::Triple::aarch64:
110 case llvm::Triple::mips64:
111 return !(getVersion() >= VersionTuple(1, 9));
112 case llvm::Triple::riscv64:
113 case llvm::Triple::riscv64be:
114 return !(getVersion() >= VersionTuple(2, 2));
115 default:
116 return true;
117 }
118 } else if ((getKind() == MacOSX) && isNonFragile() &&
119 (getVersion() >= VersionTuple(10, 0)) &&
120 (getVersion() < VersionTuple(10, 6)))
121 return Arch != llvm::Triple::x86_64;
122 // Except for deployment target of 10.5 or less,
123 // Mac runtimes use legacy dispatch everywhere now.
124 return true;
125 }
126
127 /// Is this runtime basically of the GNU family of runtimes?
128 bool isGNUFamily() const {
129 switch (getKind()) {
130 case FragileMacOSX:
131 case MacOSX:
132 case iOS:
133 case WatchOS:
134 return false;
135 case GCC:
136 case GNUstep:
137 case ObjFW:
138 return true;
139 }
140 llvm_unreachable("bad kind");
141 }
142
143 /// Is this runtime basically of the NeXT family of runtimes?
144 bool isNeXTFamily() const {
145 // For now, this is just the inverse of isGNUFamily(), but that's
146 // not inherently true.
147 return !isGNUFamily();
148 }
149
150 /// Does this runtime allow ARC at all?
151 bool allowsARC() const {
152 switch (getKind()) {
153 case FragileMacOSX:
154 // No stub library for the fragile runtime.
155 return getVersion() >= VersionTuple(10, 7);
156 case MacOSX: return true;
157 case iOS: return true;
158 case WatchOS: return true;
159 case GCC: return false;
160 case GNUstep: return true;
161 case ObjFW: return true;
162 }
163 llvm_unreachable("bad kind");
164 }
165
166 /// Does this runtime natively provide the ARC entrypoints?
167 ///
168 /// ARC cannot be directly supported on a platform that does not provide
169 /// these entrypoints, although it may be supportable via a stub
170 /// library.
171 bool hasNativeARC() const {
172 switch (getKind()) {
173 case FragileMacOSX: return getVersion() >= VersionTuple(10, 7);
174 case MacOSX: return getVersion() >= VersionTuple(10, 7);
175 case iOS: return getVersion() >= VersionTuple(5);
176 case WatchOS: return true;
177
178 case GCC: return false;
179 case GNUstep: return getVersion() >= VersionTuple(1, 6);
180 case ObjFW: return true;
181 }
182 llvm_unreachable("bad kind");
183 }
184
185 /// Does this runtime provide ARC entrypoints that are likely to be faster
186 /// than an ordinary message send of the appropriate selector?
187 ///
188 /// The ARC entrypoints are guaranteed to be equivalent to just sending the
189 /// corresponding message. If the entrypoint is implemented naively as just a
190 /// message send, using it is a trade-off: it sacrifices a few cycles of
191 /// overhead to save a small amount of code. However, it's possible for
192 /// runtimes to detect and special-case classes that use "standard"
193 /// retain/release behavior; if that's dynamically a large proportion of all
194 /// retained objects, using the entrypoint will also be faster than using a
195 /// message send.
196 ///
197 /// When this method returns true, Clang will turn non-super message sends of
198 /// certain selectors into calls to the correspond entrypoint:
199 /// retain => objc_retain
200 /// release => objc_release
201 /// autorelease => objc_autorelease
203 switch (getKind()) {
204 case FragileMacOSX:
205 return false;
206 case MacOSX:
207 return getVersion() >= VersionTuple(10, 10);
208 case iOS:
209 return getVersion() >= VersionTuple(8);
210 case WatchOS:
211 return true;
212 case GCC:
213 return false;
214 case GNUstep:
215 // This could be enabled for all versions, except for the fact that the
216 // implementation of `objc_retain` and friends prior to 2.2 call [object
217 // retain] in their fall-back paths, which leads to infinite recursion if
218 // the runtime is built with this enabled. Since distributions typically
219 // build all Objective-C things with the same compiler version and flags,
220 // it's better to be conservative here.
221 return (getVersion() >= VersionTuple(2, 2));
222 case ObjFW:
223 return false;
224 }
225 llvm_unreachable("bad kind");
226 }
227
228 /// Does this runtime provide entrypoints that are likely to be faster
229 /// than an ordinary message send of the "alloc" selector?
230 ///
231 /// The "alloc" entrypoint is guaranteed to be equivalent to just sending the
232 /// corresponding message. If the entrypoint is implemented naively as just a
233 /// message send, using it is a trade-off: it sacrifices a few cycles of
234 /// overhead to save a small amount of code. However, it's possible for
235 /// runtimes to detect and special-case classes that use "standard"
236 /// alloc behavior; if that's dynamically a large proportion of all
237 /// objects, using the entrypoint will also be faster than using a message
238 /// send.
239 ///
240 /// When this method returns true, Clang will turn non-super message sends of
241 /// certain selectors into calls to the corresponding entrypoint:
242 /// alloc => objc_alloc
243 /// allocWithZone:nil => objc_allocWithZone
245 switch (getKind()) {
246 case FragileMacOSX:
247 return false;
248 case MacOSX:
249 return getVersion() >= VersionTuple(10, 10);
250 case iOS:
251 return getVersion() >= VersionTuple(8);
252 case WatchOS:
253 return true;
254
255 case GCC:
256 return false;
257 case GNUstep:
258 return getVersion() >= VersionTuple(2, 2);
259 case ObjFW:
260 return false;
261 }
262 llvm_unreachable("bad kind");
263 }
264
265 /// Does this runtime provide the objc_alloc_init entrypoint? This can apply
266 /// the same optimization as objc_alloc, but also sends an -init message,
267 /// reducing code size on the caller.
269 switch (getKind()) {
270 case MacOSX:
271 return getVersion() >= VersionTuple(10, 14, 4);
272 case iOS:
273 return getVersion() >= VersionTuple(12, 2);
274 case WatchOS:
275 return getVersion() >= VersionTuple(5, 2);
276 case GNUstep:
277 return getVersion() >= VersionTuple(2, 2);
278 default:
279 return false;
280 }
281 }
282
283 /// Does this runtime supports optimized setter entrypoints?
284 bool hasOptimizedSetter() const {
285 switch (getKind()) {
286 case MacOSX:
287 return getVersion() >= VersionTuple(10, 8);
288 case iOS:
289 return (getVersion() >= VersionTuple(6));
290 case WatchOS:
291 return true;
292 case GNUstep:
293 return getVersion() >= VersionTuple(1, 7);
294 default:
295 return false;
296 }
297 }
298
299 /// Are Foundation backed constant literal classes supported?
301 switch (getKind()) {
302 case MacOSX:
303 return getVersion() >= VersionTuple(11);
304 case iOS:
305 return getVersion() >= VersionTuple(14);
306 case WatchOS:
307 return getVersion() >= VersionTuple(7);
308 default:
309 return false;
310 }
311 }
315 }
316
317 /// Does this runtime allow the use of __weak?
318 bool allowsWeak() const {
319 return hasNativeWeak();
320 }
321
322 /// Does this runtime natively provide ARC-compliant 'weak'
323 /// entrypoints?
324 bool hasNativeWeak() const {
325 // Right now, this is always equivalent to whether the runtime
326 // natively supports ARC decision.
327 return hasNativeARC();
328 }
329
330 /// Does this runtime directly support the subscripting methods?
331 ///
332 /// This is really a property of the library, not the runtime.
333 bool hasSubscripting() const {
334 switch (getKind()) {
335 case FragileMacOSX: return false;
336 case MacOSX: return getVersion() >= VersionTuple(10, 11);
337 case iOS: return getVersion() >= VersionTuple(9);
338 case WatchOS: return true;
339
340 // This is really a lie, because some implementations and versions
341 // of the runtime do not support ARC. Probably -fgnu-runtime
342 // should imply a "maximal" runtime or something?
343 case GCC: return true;
344 case GNUstep: return true;
345 case ObjFW: return true;
346 }
347 llvm_unreachable("bad kind");
348 }
349
350 /// Does this runtime allow sizeof or alignof on object types?
351 bool allowsSizeofAlignof() const {
352 return isFragile();
353 }
354
355 /// Does this runtime allow pointer arithmetic on objects?
356 ///
357 /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
358 /// yields true) [].
360 switch (getKind()) {
361 case FragileMacOSX:
362 case GCC:
363 return true;
364 case MacOSX:
365 case iOS:
366 case WatchOS:
367 case GNUstep:
368 case ObjFW:
369 return false;
370 }
371 llvm_unreachable("bad kind");
372 }
373
374 /// Is subscripting pointer arithmetic?
377 }
378
379 /// Does this runtime provide an objc_terminate function?
380 ///
381 /// This is used in handlers for exceptions during the unwind process;
382 /// without it, abort() must be used in pure ObjC files.
383 bool hasTerminate() const {
384 switch (getKind()) {
385 case FragileMacOSX: return getVersion() >= VersionTuple(10, 8);
386 case MacOSX: return getVersion() >= VersionTuple(10, 8);
387 case iOS: return getVersion() >= VersionTuple(5);
388 case WatchOS: return true;
389 case GCC: return false;
390 case GNUstep: return false;
391 case ObjFW: return false;
392 }
393 llvm_unreachable("bad kind");
394 }
395
396 /// Does this runtime support weakly importing classes?
397 bool hasWeakClassImport() const {
398 switch (getKind()) {
399 case MacOSX: return true;
400 case iOS: return true;
401 case WatchOS: return true;
402 case FragileMacOSX: return false;
403 case GCC: return true;
404 case GNUstep: return true;
405 case ObjFW: return true;
406 }
407 llvm_unreachable("bad kind");
408 }
409
410 /// Does this runtime use zero-cost exceptions?
411 bool hasUnwindExceptions() const {
412 switch (getKind()) {
413 case MacOSX: return true;
414 case iOS: return true;
415 case WatchOS: return true;
416 case FragileMacOSX: return false;
417 case GCC: return true;
418 case GNUstep: return true;
419 case ObjFW: return true;
420 }
421 llvm_unreachable("bad kind");
422 }
423
424 bool hasAtomicCopyHelper() const {
425 switch (getKind()) {
426 case FragileMacOSX:
427 case MacOSX:
428 case iOS:
429 case WatchOS:
430 return true;
431 case GNUstep:
432 return getVersion() >= VersionTuple(1, 7);
433 default: return false;
434 }
435 }
436
437 /// Is objc_unsafeClaimAutoreleasedReturnValue available?
439 switch (getKind()) {
440 case MacOSX:
441 case FragileMacOSX:
442 return getVersion() >= VersionTuple(10, 11);
443 case iOS:
444 return getVersion() >= VersionTuple(9);
445 case WatchOS:
446 return getVersion() >= VersionTuple(2);
447 case GNUstep:
448 return false;
449 default:
450 return false;
451 }
452 }
453
454 /// Are the empty collection symbols available?
455 bool hasEmptyCollections() const {
456 switch (getKind()) {
457 default:
458 return false;
459 case MacOSX:
460 return getVersion() >= VersionTuple(10, 11);
461 case iOS:
462 return getVersion() >= VersionTuple(9);
463 case WatchOS:
464 return getVersion() >= VersionTuple(2);
465 }
466 }
467
468 /// Returns true if this Objective-C runtime supports Objective-C class
469 /// stubs.
470 bool allowsClassStubs() const {
471 switch (getKind()) {
472 case FragileMacOSX:
473 case GCC:
474 case GNUstep:
475 case ObjFW:
476 return false;
477 case MacOSX:
478 case iOS:
479 case WatchOS:
480 return true;
481 }
482 llvm_unreachable("bad kind");
483 }
484
485 /// Does this runtime supports direct dispatch
486 bool allowsDirectDispatch() const {
487 switch (getKind()) {
488 case FragileMacOSX: return false;
489 case MacOSX: return true;
490 case iOS: return true;
491 case WatchOS: return true;
492 case GCC: return false;
493 case GNUstep:
494 return (getVersion() >= VersionTuple(2, 2));
495 case ObjFW: return true;
496 }
497 llvm_unreachable("bad kind");
498 }
499
500 /// Try to parse an Objective-C runtime specification from the given
501 /// string.
502 ///
503 /// \return true on error.
504 bool tryParse(StringRef input);
505
506 std::string getAsString() const;
507
508 friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
509 return left.getKind() == right.getKind() &&
510 left.getVersion() == right.getVersion();
511 }
512
513 friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
514 return !(left == right);
515 }
516
517 friend llvm::hash_code hash_value(const ObjCRuntime &OCR) {
518 return llvm::hash_combine(OCR.getKind(), OCR.getVersion());
519 }
520
521 template <typename HasherT, llvm::endianness Endianness>
522 friend void addHash(llvm::HashBuilder<HasherT, Endianness> &HBuilder,
523 const ObjCRuntime &OCR) {
524 HBuilder.add(OCR.getKind(), OCR.getVersion());
525 }
526};
527
528raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
529
530} // namespace clang
531
532#endif // LLVM_CLANG_BASIC_OBJCRUNTIME_H
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
bool hasConstantEmptyCollections() const
bool allowsWeak() const
Does this runtime allow the use of __weak?
bool shouldUseRuntimeFunctionsForAlloc() const
Does this runtime provide entrypoints that are likely to be faster than an ordinary message send of t...
bool hasEmptyCollections() const
Are the empty collection symbols available?
friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right)
bool hasAtomicCopyHelper() const
bool isSubscriptPointerArithmetic() const
Is subscripting pointer arithmetic?
bool shouldUseRuntimeFunctionForCombinedAllocInit() const
Does this runtime provide the objc_alloc_init entrypoint?
bool hasUnwindExceptions() const
Does this runtime use zero-cost exceptions?
friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right)
bool allowsSizeofAlignof() const
Does this runtime allow sizeof or alignof on object types?
bool hasARCUnsafeClaimAutoreleasedReturnValue() const
Is objc_unsafeClaimAutoreleasedReturnValue available?
void set(Kind kind, VersionTuple version)
Definition ObjCRuntime.h:72
bool hasTerminate() const
Does this runtime provide an objc_terminate function?
ObjCRuntime()=default
A bogus initialization of the runtime.
bool hasNativeARC() const
Does this runtime natively provide the ARC entrypoints?
bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch)
The default dispatch mechanism to use for the specified architecture.
Kind getKind() const
Definition ObjCRuntime.h:77
bool isNeXTFamily() const
Is this runtime basically of the NeXT family of runtimes?
bool hasConstantLiteralClasses() const
Are Foundation backed constant literal classes supported?
bool hasOptimizedSetter() const
Does this runtime supports optimized setter entrypoints?
bool hasNativeWeak() const
Does this runtime natively provide ARC-compliant 'weak' entrypoints?
ObjCRuntime(Kind kind, const VersionTuple &version)
Definition ObjCRuntime.h:69
bool allowsPointerArithmetic() const
Does this runtime allow pointer arithmetic on objects?
bool hasSubscripting() const
Does this runtime directly support the subscripting methods?
const VersionTuple & getVersion() const
Definition ObjCRuntime.h:78
bool tryParse(StringRef input)
Try to parse an Objective-C runtime specification from the given string.
bool isNonFragile() const
Does this runtime follow the set of implied behaviors for a "non-fragile" ABI?
Definition ObjCRuntime.h:82
std::string getAsString() const
friend llvm::hash_code hash_value(const ObjCRuntime &OCR)
bool hasWeakClassImport() const
Does this runtime support weakly importing classes?
bool hasConstantCFBooleans() const
bool isGNUFamily() const
Is this runtime basically of the GNU family of runtimes?
bool allowsARC() const
Does this runtime allow ARC at all?
bool allowsDirectDispatch() const
Does this runtime supports direct dispatch.
bool shouldUseARCFunctionsForRetainRelease() const
Does this runtime provide ARC entrypoints that are likely to be faster than an ordinary message send ...
friend void addHash(llvm::HashBuilder< HasherT, Endianness > &HBuilder, const ObjCRuntime &OCR)
Kind
The basic Objective-C runtimes that we know about.
Definition ObjCRuntime.h:31
@ MacOSX
'macosx' is the Apple-provided NeXT-derived runtime on Mac OS X platforms that use the non-fragile AB...
Definition ObjCRuntime.h:35
@ FragileMacOSX
'macosx-fragile' is the Apple-provided NeXT-derived runtime on Mac OS X platforms that use the fragil...
Definition ObjCRuntime.h:40
@ GNUstep
'gnustep' is the modern non-fragile GNUstep runtime.
Definition ObjCRuntime.h:56
@ ObjFW
'objfw' is the Objective-C runtime included in ObjFW
Definition ObjCRuntime.h:59
@ iOS
'ios' is the Apple-provided NeXT-derived runtime on iOS or the iOS simulator; it is always non-fragil...
Definition ObjCRuntime.h:45
@ GCC
'gcc' is the Objective-C runtime shipped with GCC, implementing a fragile Objective-C ABI
Definition ObjCRuntime.h:53
@ WatchOS
'watchos' is a variant of iOS for Apple's watchOS.
Definition ObjCRuntime.h:49
bool allowsClassStubs() const
Returns true if this Objective-C runtime supports Objective-C class stubs.
bool isFragile() const
The inverse of isNonFragile(): does this runtime follow the set of implied behaviors for a "fragile" ...
Definition ObjCRuntime.h:97
The JSON file list parser is used to communicate input to InstallAPI.
const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ConceptReference *C)
Insertion operator for diagnostics.