Coverage Report

Created: 2023-11-11 10:31

/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