Coverage Report

Created: 2019-02-21 13:17

/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
971k
  ObjCRuntime() = default;
68
  ObjCRuntime(Kind kind, const VersionTuple &version)
69
32.4k
      : 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.25M
  Kind getKind() const { return TheKind; }
77
82.3k
  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.17M
  bool isNonFragile() const {
82
4.17M
    switch (getKind()) {
83
4.17M
    
case FragileMacOSX: return false1.93k
;
84
4.17M
    
case GCC: return false7.83k
;
85
4.17M
    
case MacOSX: return true4.10M
;
86
4.17M
    
case GNUstep: return true1.80k
;
87
4.17M
    
case ObjFW: return true80
;
88
4.17M
    
case iOS: return true55.1k
;
89
4.17M
    
case WatchOS: return true61
;
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
169k
  bool isFragile() const { return !isNonFragile(); }
97
98
  /// The default dispatch mechanism to use for the specified architecture
99
19.9k
  bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) {
100
19.9k
    // The GNUstep runtime uses a newer dispatch method by default from
101
19.9k
    // version 1.6 onwards
102
19.9k
    if (getKind() == GNUstep && 
getVersion() >= VersionTuple(1, 6)1.41k
) {
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.9k
    }
108
19.9k
    else if ((getKind() ==  MacOSX) && 
isNonFragile()8.61k
&&
109
19.9k
             
(getVersion() >= VersionTuple(10, 0))8.61k
&&
110
19.9k
             
(getVersion() < VersionTuple(10, 6))8.61k
)
111
593
        return Arch != llvm::Triple::x86_64;
112
19.3k
    // Except for deployment target of 10.5 or less,
113
19.3k
    // 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
6.37k
  bool isGNUFamily() const {
119
6.37k
    switch (getKind()) {
120
6.37k
    case FragileMacOSX:
121
6.19k
    case MacOSX:
122
6.19k
    case iOS:
123
6.19k
    case WatchOS:
124
6.19k
      return false;
125
6.19k
    case GCC:
126
178
    case GNUstep:
127
178
    case ObjFW:
128
178
      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
5.93k
  bool isNeXTFamily() const {
135
5.93k
    // For now, this is just the inverse of isGNUFamily(), but that's
136
5.93k
    // not inherently true.
137
5.93k
    return !isGNUFamily();
138
5.93k
  }
139
140
  /// Does this runtime allow ARC at all?
141
386
  bool allowsARC() const {
142
386
    switch (getKind()) {
143
386
    case FragileMacOSX:
144
7
      // No stub library for the fragile runtime.
145
7
      return getVersion() >= VersionTuple(10, 7);
146
386
    
case MacOSX: return true355
;
147
386
    
case iOS: return true21
;
148
386
    
case WatchOS: return true2
;
149
386
    
case GCC: return false0
;
150
386
    
case GNUstep: return true1
;
151
386
    
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
3.94k
  bool hasNativeARC() const {
162
3.94k
    switch (getKind()) {
163
3.94k
    
case FragileMacOSX: return getVersion() >= VersionTuple(10, 7)317
;
164
3.94k
    
case MacOSX: return getVersion() >= VersionTuple(10, 7)3.30k
;
165
3.94k
    
case iOS: return getVersion() >= VersionTuple(5)162
;
166
3.94k
    
case WatchOS: return true19
;
167
3.94k
168
3.94k
    
case GCC: return false33
;
169
3.94k
    
case GNUstep: return getVersion() >= VersionTuple(1, 6)82
;
170
3.94k
    
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
60
  bool shouldUseARCFunctionsForRetainRelease() const {
193
60
    switch (getKind()) {
194
60
    case FragileMacOSX:
195
6
      return false;
196
60
    case MacOSX:
197
18
      return getVersion() >= VersionTuple(10, 10);
198
60
    case iOS:
199
30
      return getVersion() >= VersionTuple(8);
200
60
    case WatchOS:
201
6
      return true;
202
60
    case GCC:
203
0
      return false;
204
60
    case GNUstep:
205
0
      return false;
206
60
    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
171
  bool shouldUseRuntimeFunctionsForAlloc() const {
229
171
    switch (getKind()) {
230
171
    case FragileMacOSX:
231
18
      return false;
232
171
    case MacOSX:
233
68
      return getVersion() >= VersionTuple(10, 10);
234
171
    case iOS:
235
73
      return getVersion() >= VersionTuple(8);
236
171
    case WatchOS:
237
12
      return true;
238
171
239
171
    case GCC:
240
0
      return false;
241
171
    case GNUstep:
242
0
      return false;
243
171
    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.32k
  bool shouldUseRuntimeFunctionForCombinedAllocInit() const {
253
1.32k
    switch (getKind()) {
254
1.32k
    case MacOSX:
255
683
      return getVersion() >= VersionTuple(10, 14, 4);
256
1.32k
    case iOS:
257
374
      return getVersion() >= VersionTuple(12, 2);
258
1.32k
    case WatchOS:
259
31
      return getVersion() >= VersionTuple(5, 2);
260
1.32k
    default:
261
233
      return false;
262
1.32k
    }
263
1.32k
  }
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.33k
  bool allowsWeak() const {
283
3.33k
    return hasNativeWeak();
284
3.33k
  }
285
286
  /// Does this runtime natively provide ARC-compliant 'weak'
287
  /// entrypoints?
288
3.33k
  bool hasNativeWeak() const {
289
3.33k
    // Right now, this is always equivalent to whether the runtime
290
3.33k
    // natively supports ARC decision.
291
3.33k
    return hasNativeARC();
292
3.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
3
  bool hasSubscripting() const {
298
3
    switch (getKind()) {
299
3
    
case FragileMacOSX: return false0
;
300
3
    case MacOSX: return getVersion() >= VersionTuple(10, 11);
301
3
    
case iOS: return getVersion() >= VersionTuple(9)0
;
302
3
    
case WatchOS: return true0
;
303
3
304
3
    // This is really a lie, because some implementations and versions
305
3
    // of the runtime do not support ARC.  Probably -fgnu-runtime
306
3
    // should imply a "maximal" runtime or something?
307
3
    
case GCC: return true0
;
308
3
    
case GNUstep: return true0
;
309
3
    
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
158k
  bool allowsSizeofAlignof() const {
316
158k
    return isFragile();
317
158k
  }
318
319
  /// Does this runtime allow pointer arithmetic on objects?
320
  ///
321
  /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
322
  /// yields true) [].
323
279
  bool allowsPointerArithmetic() const {
324
279
    switch (getKind()) {
325
279
    case FragileMacOSX:
326
22
    case GCC:
327
22
      return true;
328
257
    case MacOSX:
329
257
    case iOS:
330
257
    case WatchOS:
331
257
    case GNUstep:
332
257
    case ObjFW:
333
257
      return false;
334
0
    }
335
0
    llvm_unreachable("bad kind");
336
0
  }
337
338
  /// Is subscripting pointer arithmetic?
339
263
  bool isSubscriptPointerArithmetic() const {
340
263
    return allowsPointerArithmetic();
341
263
  }
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 true60
;
366
1.97M
    
case FragileMacOSX: return false161
;
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
411
  bool hasUnwindExceptions() const {
376
411
    switch (getKind()) {
377
411
    
case MacOSX: return true108
;
378
411
    
case iOS: return true238
;
379
411
    
case WatchOS: return true15
;
380
411
    
case FragileMacOSX: return false22
;
381
411
    
case GCC: return true10
;
382
411
    
case GNUstep: return true11
;
383
411
    
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
  /// Try to parse an Objective-C runtime specification from the given
433
  /// string.
434
  ///
435
  /// \return true on error.
436
  bool tryParse(StringRef input);
437
438
  std::string getAsString() const;
439
440
4.02k
  friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
441
4.02k
    return left.getKind() == right.getKind() &&
442
4.02k
           left.getVersion() == right.getVersion();
443
4.02k
  }
444
445
4.02k
  friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
446
4.02k
    return !(left == right);
447
4.02k
  }
448
};
449
450
raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
451
452
} // namespace clang
453
454
#endif // LLVM_CLANG_BASIC_OBJCRUNTIME_H