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 22 namespace clang { 23 24 /// \brief The basic abstraction for the target Objective-C runtime. 25 class ObjCRuntime { 26 public: 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 55 private: 56 Kind TheKind; 57 VersionTuple Version; 58 59 public: 60 /// A bogus initialization of the runtime. ObjCRuntime()61 ObjCRuntime() : TheKind(MacOSX) {} 62 ObjCRuntime(Kind kind,const VersionTuple & version)63 ObjCRuntime(Kind kind, const VersionTuple &version) 64 : TheKind(kind), Version(version) {} 65 set(Kind kind,VersionTuple version)66 void set(Kind kind, VersionTuple version) { 67 TheKind = kind; 68 Version = version; 69 } 70 getKind()71 Kind getKind() const { return TheKind; } getVersion()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? isNonFragile()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? isFragile()90 bool isFragile() const { return !isNonFragile(); } 91 92 /// The default dispatch mechanism to use for the specified architecture isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch)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? isGNUFamily()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? isNeXTFamily()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? allowsARC()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. hasNativeARC()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? hasOptimizedSetter()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? allowsWeak()176 bool allowsWeak() const { 177 return hasNativeWeak(); 178 } 179 180 /// \brief Does this runtime natively provide ARC-compliant 'weak' 181 /// entrypoints? hasNativeWeak()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. hasSubscripting()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? allowsSizeofAlignof()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) []. allowsPointerArithmetic()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? isSubscriptPointerArithmetic()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. hasTerminate()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? hasWeakClassImport()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? hasUnwindExceptions()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 hasAtomicCopyHelper()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 307 raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value); 308 309 } // end namespace clang 310 311 #endif 312