Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 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/HashBuilder.h"
22
#include "llvm/Support/VersionTuple.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
  ObjCRuntime() = default;
69
  ObjCRuntime(Kind kind, const VersionTuple &version)
70
      : TheKind(kind), Version(version) {}
71
 
72
  void set(Kind kind, VersionTuple version) {
73
    TheKind = kind;
74
    Version = version;
75
  }
76
 
77
  Kind getKind() const { return TheKind; }
78
  const VersionTuple &getVersion() const { return Version; }
79
 
80
  /// Does this runtime follow the set of implied behaviors for a
81
  /// "non-fragile" ABI?
82
  bool isNonFragile() const {
83
    switch (getKind()) {
84
    case FragileMacOSX: return false;
85
    case GCC: return false;
86
    case MacOSX: return true;
87
    case GNUstep: return true;
88
    case ObjFW: return true;
89
    case iOS: return true;
90
    case WatchOS: return true;
91
    }
92
    llvm_unreachable("bad kind");
93
  }
94
 
95
  /// The inverse of isNonFragile():  does this runtime follow the set of
96
  /// implied behaviors for a "fragile" ABI?
97
  bool isFragile() const { return !isNonFragile(); }
98
 
99
  /// The default dispatch mechanism to use for the specified architecture
100
  bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) {
101
    // The GNUstep runtime uses a newer dispatch method by default from
102
    // version 1.6 onwards
103
    if (getKind() == GNUstep && getVersion() >= VersionTuple(1, 6)) {
104
      if (Arch == llvm::Triple::arm ||
105
          Arch == llvm::Triple::x86 ||
106
          Arch == llvm::Triple::x86_64)
107
        return false;
108
    }
109
    else if ((getKind() ==  MacOSX) && isNonFragile() &&
110
             (getVersion() >= VersionTuple(10, 0)) &&
111
             (getVersion() < VersionTuple(10, 6)))
112
        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
    return true;
116
  }
117
 
118
  /// Is this runtime basically of the GNU family of runtimes?
119
  bool isGNUFamily() const {
120
    switch (getKind()) {
121
    case FragileMacOSX:
122
    case MacOSX:
123
    case iOS:
124
    case WatchOS:
125
      return false;
126
    case GCC:
127
    case GNUstep:
128
    case ObjFW:
129
      return true;
130
    }
131
    llvm_unreachable("bad kind");
132
  }
133
 
134
  /// Is this runtime basically of the NeXT family of runtimes?
135
  bool isNeXTFamily() const {
136
    // For now, this is just the inverse of isGNUFamily(), but that's
137
    // not inherently true.
138
    return !isGNUFamily();
139
  }
140
 
141
  /// Does this runtime allow ARC at all?
142
  bool allowsARC() const {
143
    switch (getKind()) {
144
    case FragileMacOSX:
145
      // No stub library for the fragile runtime.
146
      return getVersion() >= VersionTuple(10, 7);
147
    case MacOSX: return true;
148
    case iOS: return true;
149
    case WatchOS: return true;
150
    case GCC: return false;
151
    case GNUstep: return true;
152
    case ObjFW: return true;
153
    }
154
    llvm_unreachable("bad kind");
155
  }
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
  bool hasNativeARC() const {
163
    switch (getKind()) {
164
    case FragileMacOSX: return getVersion() >= VersionTuple(10, 7);
165
    case MacOSX: return getVersion() >= VersionTuple(10, 7);
166
    case iOS: return getVersion() >= VersionTuple(5);
167
    case WatchOS: return true;
168
 
169
    case GCC: return false;
170
    case GNUstep: return getVersion() >= VersionTuple(1, 6);
171
    case ObjFW: return true;
172
    }
173
    llvm_unreachable("bad kind");
174
  }
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
  bool shouldUseARCFunctionsForRetainRelease() const {
194
    switch (getKind()) {
195
    case FragileMacOSX:
196
      return false;
197
    case MacOSX:
198
      return getVersion() >= VersionTuple(10, 10);
199
    case iOS:
200
      return getVersion() >= VersionTuple(8);
201
    case WatchOS:
202
      return true;
203
    case GCC:
204
      return false;
205
    case GNUstep:
206
      return false;
207
    case ObjFW:
208
      return false;
209
    }
210
    llvm_unreachable("bad kind");
211
  }
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
  bool shouldUseRuntimeFunctionsForAlloc() const {
230
    switch (getKind()) {
231
    case FragileMacOSX:
232
      return false;
233
    case MacOSX:
234
      return getVersion() >= VersionTuple(10, 10);
235
    case iOS:
236
      return getVersion() >= VersionTuple(8);
237
    case WatchOS:
238
      return true;
239
 
240
    case GCC:
241
      return false;
242
    case GNUstep:
243
      return false;
244
    case ObjFW:
245
      return false;
246
    }
247
    llvm_unreachable("bad kind");
248
  }
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
  bool shouldUseRuntimeFunctionForCombinedAllocInit() const {
254
    switch (getKind()) {
255
    case MacOSX:
256
      return getVersion() >= VersionTuple(10, 14, 4);
257
    case iOS:
258
      return getVersion() >= VersionTuple(12, 2);
259
    case WatchOS:
260
      return getVersion() >= VersionTuple(5, 2);
261
    default:
262
      return false;
263
    }
264
  }
265
 
266
  /// Does this runtime supports optimized setter entrypoints?
267
  bool hasOptimizedSetter() const {
268
    switch (getKind()) {
269
      case MacOSX:
270
        return getVersion() >= VersionTuple(10, 8);
271
      case iOS:
272
        return (getVersion() >= VersionTuple(6));
273
      case WatchOS:
274
        return true;
275
      case GNUstep:
276
        return getVersion() >= VersionTuple(1, 7);
277
      default:
278
        return false;
279
    }
280
  }
281
 
282
  /// Does this runtime allow the use of __weak?
283
  bool allowsWeak() const {
284
    return hasNativeWeak();
285
  }
286
 
287
  /// Does this runtime natively provide ARC-compliant 'weak'
288
  /// entrypoints?
289
  bool hasNativeWeak() const {
290
    // Right now, this is always equivalent to whether the runtime
291
    // natively supports ARC decision.
292
    return hasNativeARC();
293
  }
294
 
295
  /// Does this runtime directly support the subscripting methods?
296
  ///
297
  /// This is really a property of the library, not the runtime.
298
  bool hasSubscripting() const {
299
    switch (getKind()) {
300
    case FragileMacOSX: return false;
301
    case MacOSX: return getVersion() >= VersionTuple(10, 11);
302
    case iOS: return getVersion() >= VersionTuple(9);
303
    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
    case GCC: return true;
309
    case GNUstep: return true;
310
    case ObjFW: return true;
311
    }
312
    llvm_unreachable("bad kind");
313
  }
314
 
315
  /// Does this runtime allow sizeof or alignof on object types?
316
  bool allowsSizeofAlignof() const {
317
    return isFragile();
318
  }
319
 
320
  /// Does this runtime allow pointer arithmetic on objects?
321
  ///
322
  /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
323
  /// yields true) [].
324
  bool allowsPointerArithmetic() const {
325
    switch (getKind()) {
326
    case FragileMacOSX:
327
    case GCC:
328
      return true;
329
    case MacOSX:
330
    case iOS:
331
    case WatchOS:
332
    case GNUstep:
333
    case ObjFW:
334
      return false;
335
    }
336
    llvm_unreachable("bad kind");
337
  }
338
 
339
  /// Is subscripting pointer arithmetic?
340
  bool isSubscriptPointerArithmetic() const {
341
    return allowsPointerArithmetic();
342
  }
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
  bool hasTerminate() const {
349
    switch (getKind()) {
350
    case FragileMacOSX: return getVersion() >= VersionTuple(10, 8);
351
    case MacOSX: return getVersion() >= VersionTuple(10, 8);
352
    case iOS: return getVersion() >= VersionTuple(5);
353
    case WatchOS: return true;
354
    case GCC: return false;
355
    case GNUstep: return false;
356
    case ObjFW: return false;
357
    }
358
    llvm_unreachable("bad kind");
359
  }
360
 
361
  /// Does this runtime support weakly importing classes?
362
  bool hasWeakClassImport() const {
363
    switch (getKind()) {
364
    case MacOSX: return true;
365
    case iOS: return true;
366
    case WatchOS: return true;
367
    case FragileMacOSX: return false;
368
    case GCC: return true;
369
    case GNUstep: return true;
370
    case ObjFW: return true;
371
    }
372
    llvm_unreachable("bad kind");
373
  }
374
 
375
  /// Does this runtime use zero-cost exceptions?
376
  bool hasUnwindExceptions() const {
377
    switch (getKind()) {
378
    case MacOSX: return true;
379
    case iOS: return true;
380
    case WatchOS: return true;
381
    case FragileMacOSX: return false;
382
    case GCC: return true;
383
    case GNUstep: return true;
384
    case ObjFW: return true;
385
    }
386
    llvm_unreachable("bad kind");
387
  }
388
 
389
  bool hasAtomicCopyHelper() const {
390
    switch (getKind()) {
391
    case FragileMacOSX:
392
    case MacOSX:
393
    case iOS:
394
    case WatchOS:
395
      return true;
396
    case GNUstep:
397
      return getVersion() >= VersionTuple(1, 7);
398
    default: return false;
399
    }
400
  }
401
 
402
  /// Is objc_unsafeClaimAutoreleasedReturnValue available?
403
  bool hasARCUnsafeClaimAutoreleasedReturnValue() const {
404
    switch (getKind()) {
405
    case MacOSX:
406
    case FragileMacOSX:
407
      return getVersion() >= VersionTuple(10, 11);
408
    case iOS:
409
      return getVersion() >= VersionTuple(9);
410
    case WatchOS:
411
      return getVersion() >= VersionTuple(2);
412
    case GNUstep:
413
      return false;
414
    default:
415
      return false;
416
    }
417
  }
418
 
419
  /// Are the empty collection symbols available?
420
  bool hasEmptyCollections() const {
421
    switch (getKind()) {
422
    default:
423
      return false;
424
    case MacOSX:
425
      return getVersion() >= VersionTuple(10, 11);
426
    case iOS:
427
      return getVersion() >= VersionTuple(9);
428
    case WatchOS:
429
      return getVersion() >= VersionTuple(2);
430
    }
431
  }
432
 
433
  /// Returns true if this Objective-C runtime supports Objective-C class
434
  /// stubs.
435
  bool allowsClassStubs() const {
436
    switch (getKind()) {
437
    case FragileMacOSX:
438
    case GCC:
439
    case GNUstep:
440
    case ObjFW:
441
      return false;
442
    case MacOSX:
443
    case iOS:
444
    case WatchOS:
445
      return true;
446
    }
447
    llvm_unreachable("bad kind");
448
  }
449
 
450
  /// Does this runtime supports direct dispatch
451
  bool allowsDirectDispatch() const {
452
    switch (getKind()) {
453
    case FragileMacOSX: return false;
454
    case MacOSX: return true;
455
    case iOS: return true;
456
    case WatchOS: return true;
457
    case GCC: return false;
458
    case GNUstep: return false;
459
    case ObjFW: return false;
460
    }
461
    llvm_unreachable("bad kind");
462
  }
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
  friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
473
    return left.getKind() == right.getKind() &&
474
           left.getVersion() == right.getVersion();
475
  }
476
 
477
  friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
478
    return !(left == right);
479
  }
480
 
481
  friend llvm::hash_code hash_value(const ObjCRuntime &OCR) {
482
    return llvm::hash_combine(OCR.getKind(), OCR.getVersion());
483
  }
484
 
485
  template <typename HasherT, llvm::support::endianness Endianness>
486
  friend void addHash(llvm::HashBuilderImpl<HasherT, Endianness> &HBuilder,
487
                      const ObjCRuntime &OCR) {
488
    HBuilder.add(OCR.getKind(), OCR.getVersion());
489
  }
490
};
491
 
492
raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
493
 
494
} // namespace clang
495
 
496
#endif // LLVM_CLANG_BASIC_OBJCRUNTIME_H