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