Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/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
1.02M
  ObjCRuntime() = default;
68
  ObjCRuntime(Kind kind, const VersionTuple &version)
69
34.2k
      : TheKind(kind), Version(version) {}
70
71
0
  void set(Kind kind, VersionTuple version) {
72
0
    TheKind = kind;
73
0
    Version = version;
74
0
  }
75
76
6.28M
  Kind getKind() const { return TheKind; }
77
88.2k
  const VersionTuple &getVersion() const { return Version; }
78
79
  /// Does this runtime follow the set of implied behaviors for a
80
  /// "non-fragile" ABI?
81
4.19M
  bool isNonFragile() const {
82
4.19M
    switch (getKind()) {
83
4.19M
    
case FragileMacOSX: return false1.95k
;
84
4.19M
    
case GCC: return false8.24k
;
85
4.19M
    
case MacOSX: return true4.12M
;
86
4.19M
    
case GNUstep: return true1.86k
;
87
4.19M
    
case ObjFW: return true80
;
88
4.19M
    
case iOS: return true55.1k
;
89
4.19M
    
case WatchOS: return true64
;
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
186k
  bool isFragile() const { return !isNonFragile(); }
97
98
  /// The default dispatch mechanism to use for the specified architecture
99
21.2k
  bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) {
100
21.2k
    // The GNUstep runtime uses a newer dispatch method by default from
101
21.2k
    // version 1.6 onwards
102
21.2k
    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
21.2k
    }
108
21.2k
    else if ((getKind() ==  MacOSX) && 
isNonFragile()9.84k
&&
109
21.2k
             
(getVersion() >= VersionTuple(10, 0))9.84k
&&
110
21.2k
             
(getVersion() < VersionTuple(10, 6))9.84k
)
111
665
        return Arch != llvm::Triple::x86_64;
112
20.5k
    // Except for deployment target of 10.5 or less,
113
20.5k
    // Mac runtimes use legacy dispatch everywhere now.
114
20.5k
    return true;
115
20.5k
  }
116
117
  /// Is this runtime basically of the GNU family of runtimes?
118
6.45k
  bool isGNUFamily() const {
119
6.45k
    switch (getKind()) {
120
6.45k
    case FragileMacOSX:
121
6.26k
    case MacOSX:
122
6.26k
    case iOS:
123
6.26k
    case WatchOS:
124
6.26k
      return false;
125
6.26k
    case GCC:
126
189
    case GNUstep:
127
189
    case ObjFW:
128
189
      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
6.01k
  bool isNeXTFamily() const {
135
6.01k
    // For now, this is just the inverse of isGNUFamily(), but that's
136
6.01k
    // not inherently true.
137
6.01k
    return !isGNUFamily();
138
6.01k
  }
139
140
  /// Does this runtime allow ARC at all?
141
397
  bool allowsARC() const {
142
397
    switch (getKind()) {
143
397
    case FragileMacOSX:
144
7
      // No stub library for the fragile runtime.
145
7
      return getVersion() >= VersionTuple(10, 7);
146
397
    
case MacOSX: return true366
;
147
397
    
case iOS: return true21
;
148
397
    
case WatchOS: return true2
;
149
397
    
case GCC: return false0
;
150
397
    
case GNUstep: return true1
;
151
397
    
case ObjFW: return true0
;
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
4.00k
  bool hasNativeARC() const {
162
4.00k
    switch (getKind()) {
163
4.00k
    
case FragileMacOSX: return getVersion() >= VersionTuple(10, 7)320
;
164
4.00k
    
case MacOSX: return getVersion() >= VersionTuple(10, 7)3.35k
;
165
4.00k
    
case iOS: return getVersion() >= VersionTuple(5)160
;
166
4.00k
    
case WatchOS: return true19
;
167
4.00k
168
4.00k
    
case GCC: return false33
;
169
4.00k
    
case GNUstep: return getVersion() >= VersionTuple(1, 6)93
;
170
4.00k
    
case ObjFW: return true24
;
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
81
  bool shouldUseARCFunctionsForRetainRelease() const {
193
81
    switch (getKind()) {
194
81
    case FragileMacOSX:
195
9
      return false;
196
81
    case MacOSX:
197
24
      return getVersion() >= VersionTuple(10, 10);
198
81
    case iOS:
199
39
      return getVersion() >= VersionTuple(8);
200
81
    case WatchOS:
201
9
      return true;
202
81
    case GCC:
203
0
      return false;
204
81
    case GNUstep:
205
0
      return false;
206
81
    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
203
  bool shouldUseRuntimeFunctionsForAlloc() const {
229
203
    switch (getKind()) {
230
203
    case FragileMacOSX:
231
22
      return false;
232
203
    case MacOSX:
233
78
      return getVersion() >= VersionTuple(10, 10);
234
203
    case iOS:
235
87
      return getVersion() >= VersionTuple(8);
236
203
    case WatchOS:
237
16
      return true;
238
203
239
203
    case GCC:
240
0
      return false;
241
203
    case GNUstep:
242
0
      return false;
243
203
    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
1.41k
  bool shouldUseRuntimeFunctionForCombinedAllocInit() const {
253
1.41k
    switch (getKind()) {
254
1.41k
    case MacOSX:
255
727
      return getVersion() >= VersionTuple(10, 14, 4);
256
1.41k
    case iOS:
257
409
      return getVersion() >= VersionTuple(12, 2);
258
1.41k
    case WatchOS:
259
40
      return getVersion() >= VersionTuple(5, 2);
260
1.41k
    default:
261
242
      return false;
262
1.41k
    }
263
1.41k
  }
264
265
  /// Does this runtime supports optimized setter entrypoints?
266
82
  bool hasOptimizedSetter() const {
267
82
    switch (getKind()) {
268
82
      case MacOSX:
269
66
        return getVersion() >= VersionTuple(10, 8);
270
82
      case iOS:
271
12
        return (getVersion() >= VersionTuple(6));
272
82
      case WatchOS:
273
0
        return true;
274
82
      case GNUstep:
275
4
        return getVersion() >= VersionTuple(1, 7);
276
82
      default:
277
0
        return false;
278
82
    }
279
82
  }
280
281
  /// Does this runtime allow the use of __weak?
282
3.39k
  bool allowsWeak() const {
283
3.39k
    return hasNativeWeak();
284
3.39k
  }
285
286
  /// Does this runtime natively provide ARC-compliant 'weak'
287
  /// entrypoints?
288
3.39k
  bool hasNativeWeak() const {
289
3.39k
    // Right now, this is always equivalent to whether the runtime
290
3.39k
    // natively supports ARC decision.
291
3.39k
    return hasNativeARC();
292
3.39k
  }
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
4
    
case FragileMacOSX: return false0
;
300
4
    case MacOSX: return getVersion() >= VersionTuple(10, 11);
301
4
    
case iOS: return getVersion() >= VersionTuple(9)0
;
302
4
    
case WatchOS: return true0
;
303
4
304
4
    // This is really a lie, because some implementations and versions
305
4
    // of the runtime do not support ARC.  Probably -fgnu-runtime
306
4
    // should imply a "maximal" runtime or something?
307
4
    
case GCC: return true0
;
308
4
    
case GNUstep: return true0
;
309
4
    
case ObjFW: return true0
;
310
0
    }
311
0
    llvm_unreachable("bad kind");
312
0
  }
313
314
  /// Does this runtime allow sizeof or alignof on object types?
315
175k
  bool allowsSizeofAlignof() const {
316
175k
    return isFragile();
317
175k
  }
318
319
  /// Does this runtime allow pointer arithmetic on objects?
320
  ///
321
  /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
322
  /// yields true) [].
323
283
  bool allowsPointerArithmetic() const {
324
283
    switch (getKind()) {
325
283
    case FragileMacOSX:
326
22
    case GCC:
327
22
      return true;
328
261
    case MacOSX:
329
261
    case iOS:
330
261
    case WatchOS:
331
261
    case GNUstep:
332
261
    case ObjFW:
333
261
      return false;
334
0
    }
335
0
    llvm_unreachable("bad kind");
336
0
  }
337
338
  /// Is subscripting pointer arithmetic?
339
267
  bool isSubscriptPointerArithmetic() const {
340
267
    return allowsPointerArithmetic();
341
267
  }
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
12
  bool hasTerminate() const {
348
12
    switch (getKind()) {
349
12
    
case FragileMacOSX: return getVersion() >= VersionTuple(10, 8)2
;
350
12
    
case MacOSX: return getVersion() >= VersionTuple(10, 8)1
;
351
12
    
case iOS: return getVersion() >= VersionTuple(5)9
;
352
12
    
case WatchOS: return true0
;
353
12
    
case GCC: return false0
;
354
12
    
case GNUstep: return false0
;
355
12
    
case ObjFW: return false0
;
356
0
    }
357
0
    llvm_unreachable("bad kind");
358
0
  }
359
360
  /// Does this runtime support weakly importing classes?
361
1.97M
  bool hasWeakClassImport() const {
362
1.97M
    switch (getKind()) {
363
1.97M
    
case MacOSX: return true1.95M
;
364
1.97M
    
case iOS: return true19.3k
;
365
1.97M
    
case WatchOS: return true68
;
366
1.97M
    
case FragileMacOSX: return false168
;
367
1.97M
    
case GCC: return true12
;
368
1.97M
    
case GNUstep: return true6
;
369
1.97M
    
case ObjFW: return true12
;
370
0
    }
371
0
    llvm_unreachable("bad kind");
372
0
  }
373
374
  /// Does this runtime use zero-cost exceptions?
375
483
  bool hasUnwindExceptions() const {
376
483
    switch (getKind()) {
377
483
    
case MacOSX: return true137
;
378
483
    
case iOS: return true267
;
379
483
    
case WatchOS: return true22
;
380
483
    
case FragileMacOSX: return false29
;
381
483
    
case GCC: return true10
;
382
483
    
case GNUstep: return true11
;
383
483
    
case ObjFW: return true7
;
384
0
    }
385
0
    llvm_unreachable("bad kind");
386
0
  }
387
388
59
  bool hasAtomicCopyHelper() const {
389
59
    switch (getKind()) {
390
59
    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
55
  bool hasARCUnsafeClaimAutoreleasedReturnValue() const {
403
55
    switch (getKind()) {
404
55
    case MacOSX:
405
23
    case FragileMacOSX:
406
23
      return getVersion() >= VersionTuple(10, 11);
407
32
    case iOS:
408
32
      return getVersion() >= VersionTuple(9);
409
23
    case WatchOS:
410
0
      return getVersion() >= VersionTuple(2);
411
23
    case GNUstep:
412
0
      return false;
413
23
    default:
414
0
      return false;
415
55
    }
416
55
  }
417
418
  /// Are the empty collection symbols available?
419
50
  bool hasEmptyCollections() const {
420
50
    switch (getKind()) {
421
50
    default:
422
0
      return false;
423
50
    case MacOSX:
424
26
      return getVersion() >= VersionTuple(10, 11);
425
50
    case iOS:
426
16
      return getVersion() >= VersionTuple(9);
427
50
    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
12
    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
  /// Try to parse an Objective-C runtime specification from the given
450
  /// string.
451
  ///
452
  /// \return true on error.
453
  bool tryParse(StringRef input);
454
455
  std::string getAsString() const;
456
457
4.09k
  friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
458
4.09k
    return left.getKind() == right.getKind() &&
459
4.09k
           left.getVersion() == right.getVersion();
460
4.09k
  }
461
462
4.09k
  friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
463
4.09k
    return !(left == right);
464
4.09k
  }
465
};
466
467
raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
468
469
} // namespace clang
470
471
#endif // LLVM_CLANG_BASIC_OBJCRUNTIME_H