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