ObjCRuntime.h revision 252723
1//===--- ObjCRuntime.h - Objective-C Runtime Configuration ------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief Defines types useful for describing an Objective-C runtime.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_OBJCRUNTIME_H
16#define LLVM_CLANG_OBJCRUNTIME_H
17
18#include "clang/Basic/VersionTuple.h"
19#include "llvm/ADT/Triple.h"
20#include "llvm/Support/ErrorHandling.h"
21
22namespace clang {
23
24/// \brief The basic abstraction for the target Objective-C runtime.
25class ObjCRuntime {
26public:
27  /// \brief The basic Objective-C runtimes that we know about.
28  enum Kind {
29    /// 'macosx' is the Apple-provided NeXT-derived runtime on Mac OS
30    /// X platforms that use the non-fragile ABI; the version is a
31    /// release of that OS.
32    MacOSX,
33
34    /// 'macosx-fragile' is the Apple-provided NeXT-derived runtime on
35    /// Mac OS X platforms that use the fragile ABI; the version is a
36    /// release of that OS.
37    FragileMacOSX,
38
39    /// 'ios' is the Apple-provided NeXT-derived runtime on iOS or the iOS
40    /// simulator;  it is always non-fragile.  The version is a release
41    /// version of iOS.
42    iOS,
43
44    /// 'gcc' is the Objective-C runtime shipped with GCC, implementing a
45    /// fragile Objective-C ABI
46    GCC,
47
48    /// 'gnustep' is the modern non-fragile GNUstep runtime.
49    GNUstep,
50
51    /// 'objfw' is the Objective-C runtime included in ObjFW
52    ObjFW
53  };
54
55private:
56  Kind TheKind;
57  VersionTuple Version;
58
59public:
60  /// A bogus initialization of the runtime.
61  ObjCRuntime() : TheKind(MacOSX) {}
62
63  ObjCRuntime(Kind kind, const VersionTuple &version)
64    : TheKind(kind), Version(version) {}
65
66  void set(Kind kind, VersionTuple version) {
67    TheKind = kind;
68    Version = version;
69  }
70
71  Kind getKind() const { return TheKind; }
72  const VersionTuple &getVersion() const { return Version; }
73
74  /// \brief Does this runtime follow the set of implied behaviors for a
75  /// "non-fragile" ABI?
76  bool isNonFragile() const {
77    switch (getKind()) {
78    case FragileMacOSX: return false;
79    case GCC: return false;
80    case MacOSX: return true;
81    case GNUstep: return true;
82    case ObjFW: return false;
83    case iOS: return true;
84    }
85    llvm_unreachable("bad kind");
86  }
87
88  /// The inverse of isNonFragile():  does this runtime follow the set of
89  /// implied behaviors for a "fragile" ABI?
90  bool isFragile() const { return !isNonFragile(); }
91
92  /// The default dispatch mechanism to use for the specified architecture
93  bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) {
94    // The GNUstep runtime uses a newer dispatch method by default from
95    // version 1.6 onwards
96    if (getKind() == GNUstep && getVersion() >= VersionTuple(1, 6)) {
97      if (Arch == llvm::Triple::arm ||
98          Arch == llvm::Triple::x86 ||
99          Arch == llvm::Triple::x86_64)
100        return false;
101      // Mac runtimes use legacy dispatch everywhere except x86-64
102    } else if (isNeXTFamily() && isNonFragile())
103        return Arch != llvm::Triple::x86_64;
104    return true;
105  }
106
107  /// \brief Is this runtime basically of the GNU family of runtimes?
108  bool isGNUFamily() const {
109    switch (getKind()) {
110    case FragileMacOSX:
111    case MacOSX:
112    case iOS:
113      return false;
114    case GCC:
115    case GNUstep:
116    case ObjFW:
117      return true;
118    }
119    llvm_unreachable("bad kind");
120  }
121
122  /// \brief Is this runtime basically of the NeXT family of runtimes?
123  bool isNeXTFamily() const {
124    // For now, this is just the inverse of isGNUFamily(), but that's
125    // not inherently true.
126    return !isGNUFamily();
127  }
128
129  /// \brief Does this runtime allow ARC at all?
130  bool allowsARC() const {
131    switch (getKind()) {
132    case FragileMacOSX: return false;
133    case MacOSX: return true;
134    case iOS: return true;
135    case GCC: return false;
136    case GNUstep: return true;
137    case ObjFW: return true;
138    }
139    llvm_unreachable("bad kind");
140  }
141
142  /// \brief Does this runtime natively provide the ARC entrypoints?
143  ///
144  /// ARC cannot be directly supported on a platform that does not provide
145  /// these entrypoints, although it may be supportable via a stub
146  /// library.
147  bool hasNativeARC() const {
148    switch (getKind()) {
149    case FragileMacOSX: return false;
150    case MacOSX: return getVersion() >= VersionTuple(10, 7);
151    case iOS: return getVersion() >= VersionTuple(5);
152
153    case GCC: return false;
154    case GNUstep: return getVersion() >= VersionTuple(1, 6);
155    case ObjFW: return true;
156    }
157    llvm_unreachable("bad kind");
158  }
159
160  /// \brief Does this runtime supports optimized setter entrypoints?
161  bool hasOptimizedSetter() const {
162    switch (getKind()) {
163      case MacOSX:
164        return getVersion() >= VersionTuple(10, 8);
165      case iOS:
166        return (getVersion() >= VersionTuple(6));
167      case GNUstep:
168        return getVersion() >= VersionTuple(1, 7);
169
170      default:
171      return false;
172    }
173  }
174
175  /// Does this runtime allow the use of __weak?
176  bool allowsWeak() const {
177    return hasNativeWeak();
178  }
179
180  /// \brief Does this runtime natively provide ARC-compliant 'weak'
181  /// entrypoints?
182  bool hasNativeWeak() const {
183    // Right now, this is always equivalent to whether the runtime
184    // natively supports ARC decision.
185    return hasNativeARC();
186  }
187
188  /// \brief Does this runtime directly support the subscripting methods?
189  ///
190  /// This is really a property of the library, not the runtime.
191  bool hasSubscripting() const {
192    switch (getKind()) {
193    case FragileMacOSX: return false;
194    case MacOSX: return getVersion() >= VersionTuple(10, 8);
195    case iOS: return getVersion() >= VersionTuple(6);
196
197    // This is really a lie, because some implementations and versions
198    // of the runtime do not support ARC.  Probably -fgnu-runtime
199    // should imply a "maximal" runtime or something?
200    case GCC: return true;
201    case GNUstep: return true;
202    case ObjFW: return true;
203    }
204    llvm_unreachable("bad kind");
205  }
206
207  /// \brief Does this runtime allow sizeof or alignof on object types?
208  bool allowsSizeofAlignof() const {
209    return isFragile();
210  }
211
212  /// \brief Does this runtime allow pointer arithmetic on objects?
213  ///
214  /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
215  /// yields true) [].
216  bool allowsPointerArithmetic() const {
217    switch (getKind()) {
218    case FragileMacOSX:
219    case GCC:
220      return true;
221    case MacOSX:
222    case iOS:
223    case GNUstep:
224    case ObjFW:
225      return false;
226    }
227    llvm_unreachable("bad kind");
228  }
229
230  /// \brief Is subscripting pointer arithmetic?
231  bool isSubscriptPointerArithmetic() const {
232    return allowsPointerArithmetic();
233  }
234
235  /// \brief Does this runtime provide an objc_terminate function?
236  ///
237  /// This is used in handlers for exceptions during the unwind process;
238  /// without it, abort() must be used in pure ObjC files.
239  bool hasTerminate() const {
240    switch (getKind()) {
241    case FragileMacOSX: return getVersion() >= VersionTuple(10, 8);
242    case MacOSX: return getVersion() >= VersionTuple(10, 8);
243    case iOS: return getVersion() >= VersionTuple(5);
244    case GCC: return false;
245    case GNUstep: return false;
246    case ObjFW: return false;
247    }
248    llvm_unreachable("bad kind");
249  }
250
251  /// \brief Does this runtime support weakly importing classes?
252  bool hasWeakClassImport() const {
253    switch (getKind()) {
254    case MacOSX: return true;
255    case iOS: return true;
256    case FragileMacOSX: return false;
257    case GCC: return true;
258    case GNUstep: return true;
259    case ObjFW: return true;
260    }
261    llvm_unreachable("bad kind");
262  }
263
264  /// \brief Does this runtime use zero-cost exceptions?
265  bool hasUnwindExceptions() const {
266    switch (getKind()) {
267    case MacOSX: return true;
268    case iOS: return true;
269    case FragileMacOSX: return false;
270    case GCC: return true;
271    case GNUstep: return true;
272    case ObjFW: return true;
273    }
274    llvm_unreachable("bad kind");
275  }
276
277  bool hasAtomicCopyHelper() const {
278    switch (getKind()) {
279    case FragileMacOSX:
280    case MacOSX:
281    case iOS:
282      return true;
283    case GNUstep:
284      return getVersion() >= VersionTuple(1, 7);
285    default: return false;
286    }
287  }
288
289  /// \brief Try to parse an Objective-C runtime specification from the given
290  /// string.
291  ///
292  /// \return true on error.
293  bool tryParse(StringRef input);
294
295  std::string getAsString() const;
296
297  friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) {
298    return left.getKind() == right.getKind() &&
299           left.getVersion() == right.getVersion();
300  }
301
302  friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) {
303    return !(left == right);
304  }
305};
306
307raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value);
308
309}  // end namespace clang
310
311#endif
312