Coverage Report

Created: 2020-09-19 12:23

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