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 /// Does this runtime allow the use of __weak?
300 bool allowsWeak() const {
301 return hasNativeWeak();
302 }
303
304 /// Does this runtime natively provide ARC-compliant 'weak'
305 /// entrypoints?
306 bool hasNativeWeak() const {
307 // Right now, this is always equivalent to whether the runtime
308 // natively supports ARC decision.
309 return hasNativeARC();
310 }
311
312 /// Does this runtime directly support the subscripting methods?
313 ///
314 /// This is really a property of the library, not the runtime.
315 bool hasSubscripting() const {
316 switch (getKind()) {
317 case FragileMacOSX: return false;
318 case MacOSX: return getVersion() >= VersionTuple(10, 11);
319 case iOS: return getVersion() >= VersionTuple(9);
320 case WatchOS: return true;
321
322 // This is really a lie, because some implementations and versions
323 // of the runtime do not support ARC. Probably -fgnu-runtime
324 // should imply a "maximal" runtime or something?
325 case GCC: return true;
326 case GNUstep: return true;
327 case ObjFW: return true;
328 }
329 llvm_unreachable("bad kind");
330 }
331
332 /// Does this runtime allow sizeof or alignof on object types?
333 bool allowsSizeofAlignof() const {
334 return isFragile();
335 }
336
337 /// Does this runtime allow pointer arithmetic on objects?
338 ///
339 /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
340 /// yields true) [].
342 switch (getKind()) {
343 case FragileMacOSX:
344 case GCC:
345 return true;
346 case MacOSX:
347 case iOS:
348 case WatchOS:
349 case GNUstep:
350 case ObjFW:
351 return false;
352 }
353 llvm_unreachable("bad kind");
354 }
355
356 /// Is subscripting pointer arithmetic?
359 }
360
361 /// Does this runtime provide an objc_terminate function?
362 ///
363 /// This is used in handlers for exceptions during the unwind process;
364 /// without it, abort() must be used in pure ObjC files.
365 bool hasTerminate() const {
366 switch (getKind()) {
367 case FragileMacOSX: return getVersion() >= VersionTuple(10, 8);
368 case MacOSX: return getVersion() >= VersionTuple(10, 8);
369 case iOS: return getVersion() >= VersionTuple(5);
370 case WatchOS: return true;
371 case GCC: return false;
372 case GNUstep: return false;
373 case ObjFW: return false;
374 }
375 llvm_unreachable("bad kind");
376 }
377
378 /// Does this runtime support weakly importing classes?
379 bool hasWeakClassImport() const {
380 switch (getKind()) {
381 case MacOSX: return true;
382 case iOS: return true;
383 case WatchOS: return true;
384 case FragileMacOSX: return false;
385 case GCC: return true;
386 case GNUstep: return true;
387 case ObjFW: return true;
388 }
389 llvm_unreachable("bad kind");
390 }
391
392 /// Does this runtime use zero-cost exceptions?
393 bool hasUnwindExceptions() const {
394 switch (getKind()) {
395 case MacOSX: return true;
396 case iOS: return true;
397 case WatchOS: return true;
398 case FragileMacOSX: return false;
399 case GCC: return true;
400 case GNUstep: return true;
401 case ObjFW: return true;
402 }
403 llvm_unreachable("bad kind");
404 }
405
406 bool hasAtomicCopyHelper() const {
407 switch (getKind()) {
408 case FragileMacOSX:
409 case MacOSX:
410 case iOS:
411 case WatchOS:
412 return true;
413 case GNUstep:
414 return getVersion() >= VersionTuple(1, 7);
415 default: return false;
416 }
417 }
418
419 /// Is objc_unsafeClaimAutoreleasedReturnValue available?
421 switch (getKind()) {
422 case MacOSX:
423 case FragileMacOSX:
424 return getVersion() >= VersionTuple(10, 11);
425 case iOS:
426 return getVersion() >= VersionTuple(9);
427 case WatchOS:
428 return getVersion() >= VersionTuple(2);
429 case GNUstep:
430 return false;
431 default:
432 return false;
433 }
434 }
435
436 /// Are the empty collection symbols available?
437 bool hasEmptyCollections() const {
438 switch (getKind()) {
439 default:
440 return false;
441 case MacOSX:
442 return getVersion() >= VersionTuple(10, 11);
443 case iOS:
444 return getVersion() >= VersionTuple(9);
445 case WatchOS:
446 return getVersion() >= VersionTuple(2);
447 }
448 }
449
450 /// Returns true if this Objective-C runtime supports Objective-C class
451 /// stubs.
452 bool allowsClassStubs() const {
453 switch (getKind()) {
454 case FragileMacOSX:
455 case GCC:
456 case GNUstep:
457 case ObjFW:
458 return false;
459 case MacOSX:
460 case iOS:
461 case WatchOS:
462 return true;
463 }
464 llvm_unreachable("bad kind");
465 }
466
467 /// Does this runtime supports direct dispatch
468 bool allowsDirectDispatch() const {
469 switch (getKind()) {
470 case FragileMacOSX: return false;
471 case MacOSX: return true;
472 case iOS: return true;
473 case WatchOS: return true;
474 case GCC: return false;
475 case GNUstep:
476 return (getVersion() >= VersionTuple(2, 2));
477 case ObjFW: return true;
478 }
479 llvm_unreachable("bad kind");
480 }
481
482 /// Try to parse an Objective-C runtime specification from the given
483 /// string.
484 ///
485 /// \return true on error.
486 bool tryParse(StringRef input);
487
488 std::string getAsString() const;
489
490 friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
491 return left.getKind() == right.getKind() &&
492 left.getVersion() == right.getVersion();
493 }
494
495 friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
496 return !(left == right);
497 }
498
499 friend llvm::hash_code hash_value(const ObjCRuntime &OCR) {
500 return llvm::hash_combine(OCR.getKind(), OCR.getVersion());
501 }
502
503 template <typename HasherT, llvm::endianness Endianness>
504 friend void addHash(llvm::HashBuilder<HasherT, Endianness> &HBuilder,
505 const ObjCRuntime &OCR) {
506 HBuilder.add(OCR.getKind(), OCR.getVersion());
507 }
508};
509
510raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
511
512} // namespace clang
513
514#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 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 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 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.