Coverage Report

Created: 2020-02-25 14:32

/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
3.95M
  ObjCRuntime() = default;
68
  ObjCRuntime(Kind kind, const VersionTuple &version)
69
34.3k
      : TheKind(kind), Version(version) {}
70
71
10.3k
  void set(Kind kind, VersionTuple version) {
72
10.3k
    TheKind = kind;
73
10.3k
    Version = version;
74
10.3k
  }
75
76
4.43M
  Kind getKind() const { return TheKind; }
77
118k
  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.95M
  bool isNonFragile() const {
82
2.95M
    switch (getKind()) {
83
1.78k
    case FragileMacOSX: return false;
84
8.84k
    case GCC: return false;
85
2.94M
    case MacOSX: return true;
86
1.25k
    case GNUstep: return true;
87
80
    case ObjFW: return true;
88
429
    case iOS: return true;
89
67
    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
134k
  bool isFragile() const { return !isNonFragile(); }
97
98
  /// The default dispatch mechanism to use for the specified architecture
99
17.8k
  bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) {
100
17.8k
    // The GNUstep runtime uses a newer dispatch method by default from
101
17.8k
    // version 1.6 onwards
102
17.8k
    if (getKind() == GNUstep && 
getVersion() >= VersionTuple(1, 6)743
) {
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
17.8k
    }
108
17.8k
    else if ((getKind() ==  MacOSX) && 
isNonFragile()16.8k
&&
109
17.8k
             
(getVersion() >= VersionTuple(10, 0))16.8k
&&
110
17.8k
             
(getVersion() < VersionTuple(10, 6))16.8k
)
111
25
        return Arch != llvm::Triple::x86_64;
112
17.8k
    // Except for deployment target of 10.5 or less,
113
17.8k
    // Mac runtimes use legacy dispatch everywhere now.
114
17.8k
    return true;
115
17.8k
  }
116
117
  /// Is this runtime basically of the GNU family of runtimes?
118
19.1k
  bool isGNUFamily() const {
119
19.1k
    switch (getKind()) {
120
18.8k
    case FragileMacOSX:
121
18.8k
    case MacOSX:
122
18.8k
    case iOS:
123
18.8k
    case WatchOS:
124
18.8k
      return false;
125
18.8k
    case GCC:
126
235
    case GNUstep:
127
235
    case ObjFW:
128
235
      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
18.6k
  bool isNeXTFamily() const {
135
18.6k
    // For now, this is just the inverse of isGNUFamily(), but that's
136
18.6k
    // not inherently true.
137
18.6k
    return !isGNUFamily();
138
18.6k
  }
139
140
  /// Does this runtime allow ARC at all?
141
1.57k
  bool allowsARC() const {
142
1.57k
    switch (getKind()) {
143
7
    case FragileMacOSX:
144
7
      // No stub library for the fragile runtime.
145
7
      return getVersion() >= VersionTuple(10, 7);
146
1.53k
    case MacOSX: return true;
147
21
    case iOS: return true;
148
2
    case WatchOS: return true;
149
5
    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
6.49k
  bool hasNativeARC() const {
162
6.49k
    switch (getKind()) {
163
320
    case FragileMacOSX: return getVersion() >= VersionTuple(10, 7);
164
5.83k
    case MacOSX: return getVersion() >= VersionTuple(10, 7);
165
124
    case iOS: return getVersion() >= VersionTuple(5);
166
19
    case WatchOS: return true;
167
0
168
38
    case GCC: return false;
169
134
    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.46k
  bool shouldUseRuntimeFunctionsForAlloc() const {
229
1.46k
    switch (getKind()) {
230
22
    case FragileMacOSX:
231
22
      return false;
232
1.37k
    case MacOSX:
233
1.37k
      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
135
    case iOS:
257
135
      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
5.51k
  bool allowsWeak() const {
283
5.51k
    return hasNativeWeak();
284
5.51k
  }
285
286
  /// Does this runtime natively provide ARC-compliant 'weak'
287
  /// entrypoints?
288
5.51k
  bool hasNativeWeak() const {
289
5.51k
    // Right now, this is always equivalent to whether the runtime
290
5.51k
    // natively supports ARC decision.
291
5.51k
    return hasNativeARC();
292
5.51k
  }
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
0
    // This is really a lie, because some implementations and versions
305
0
    // of the runtime do not support ARC.  Probably -fgnu-runtime
306
0
    // 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
77.8k
  bool allowsSizeofAlignof() const {
316
77.8k
    return isFragile();
317
77.8k
  }
318
319
  /// Does this runtime allow pointer arithmetic on objects?
320
  ///
321
  /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
322
  /// yields true) [].
323
599
  bool allowsPointerArithmetic() const {
324
599
    switch (getKind()) {
325
28
    case FragileMacOSX:
326
28
    case GCC:
327
28
      return true;
328
571
    case MacOSX:
329
571
    case iOS:
330
571
    case WatchOS:
331
571
    case GNUstep:
332
571
    case ObjFW:
333
571
      return false;
334
0
    }
335
0
    llvm_unreachable("bad kind");
336
0
  }
337
338
  /// Is subscripting pointer arithmetic?
339
583
  bool isSubscriptPointerArithmetic() const {
340
583
    return allowsPointerArithmetic();
341
583
  }
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
1.29M
  bool hasWeakClassImport() const {
362
1.29M
    switch (getKind()) {
363
1.29M
    case MacOSX: return true;
364
310
    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.08k
  bool hasUnwindExceptions() const {
376
2.08k
    switch (getKind()) {
377
1.92k
    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
59
  bool hasAtomicCopyHelper() const {
389
59
    switch (getKind()) {
390
55
    case FragileMacOSX:
391
55
    case MacOSX:
392
55
    case iOS:
393
55
    case WatchOS:
394
55
      return true;
395
55
    case GNUstep:
396
4
      return getVersion() >= VersionTuple(1, 7);
397
55
    
default: return false0
;
398
59
    }
399
59
  }
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
27
    case WatchOS:
410
0
      return getVersion() >= VersionTuple(2);
411
27
    case GNUstep:
412
0
      return false;
413
27
    default:
414
0
      return false;
415
59
    }
416
59
  }
417
418
  /// Are the empty collection symbols available?
419
50
  bool hasEmptyCollections() const {
420
50
    switch (getKind()) {
421
0
    default:
422
0
      return false;
423
26
    case MacOSX:
424
26
      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
50
    }
430
50
  }
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
145
  bool allowsDirectDispatch() const {
451
145
    switch (getKind()) {
452
0
    case FragileMacOSX: return false;
453
145
    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.19k
  friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
472
7.19k
    return left.getKind() == right.getKind() &&
473
7.19k
           left.getVersion() == right.getVersion();
474
7.19k
  }
475
476
7.19k
  friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
477
7.19k
    return !(left == right);
478
7.19k
  }
479
};
480
481
raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
482
483
} // namespace clang
484
485
#endif // LLVM_CLANG_BASIC_OBJCRUNTIME_H