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_BASIC_OBJCRUNTIME_H 16 #define LLVM_CLANG_BASIC_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 /// 'watchos' is a variant of iOS for Apple's watchOS. The version 45 /// is a release version of watchOS. 46 WatchOS, 47 48 /// 'gcc' is the Objective-C runtime shipped with GCC, implementing a 49 /// fragile Objective-C ABI 50 GCC, 51 52 /// 'gnustep' is the modern non-fragile GNUstep runtime. 53 GNUstep, 54 55 /// 'objfw' is the Objective-C runtime included in ObjFW 56 ObjFW 57 }; 58 59 private: 60 Kind TheKind; 61 VersionTuple Version; 62 63 public: 64 /// A bogus initialization of the runtime. ObjCRuntime()65 ObjCRuntime() : TheKind(MacOSX) {} 66 ObjCRuntime(Kind kind,const VersionTuple & version)67 ObjCRuntime(Kind kind, const VersionTuple &version) 68 : TheKind(kind), Version(version) {} 69 set(Kind kind,VersionTuple version)70 void set(Kind kind, VersionTuple version) { 71 TheKind = kind; 72 Version = version; 73 } 74 getKind()75 Kind getKind() const { return TheKind; } getVersion()76 const VersionTuple &getVersion() const { return Version; } 77 78 /// \brief Does this runtime follow the set of implied behaviors for a 79 /// "non-fragile" ABI? isNonFragile()80 bool isNonFragile() const { 81 switch (getKind()) { 82 case FragileMacOSX: return false; 83 case GCC: return false; 84 case MacOSX: return true; 85 case GNUstep: return true; 86 case ObjFW: return true; 87 case iOS: return true; 88 case WatchOS: return true; 89 } 90 llvm_unreachable("bad kind"); 91 } 92 93 /// The inverse of isNonFragile(): does this runtime follow the set of 94 /// implied behaviors for a "fragile" ABI? isFragile()95 bool isFragile() const { return !isNonFragile(); } 96 97 /// The default dispatch mechanism to use for the specified architecture isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch)98 bool isLegacyDispatchDefaultForArch(llvm::Triple::ArchType Arch) { 99 // The GNUstep runtime uses a newer dispatch method by default from 100 // version 1.6 onwards 101 if (getKind() == GNUstep && getVersion() >= VersionTuple(1, 6)) { 102 if (Arch == llvm::Triple::arm || 103 Arch == llvm::Triple::x86 || 104 Arch == llvm::Triple::x86_64) 105 return false; 106 } 107 else if ((getKind() == MacOSX) && isNonFragile() && 108 (getVersion() >= VersionTuple(10, 0)) && 109 (getVersion() < VersionTuple(10, 6))) 110 return Arch != llvm::Triple::x86_64; 111 // Except for deployment target of 10.5 or less, 112 // Mac runtimes use legacy dispatch everywhere now. 113 return true; 114 } 115 116 /// \brief Is this runtime basically of the GNU family of runtimes? isGNUFamily()117 bool isGNUFamily() const { 118 switch (getKind()) { 119 case FragileMacOSX: 120 case MacOSX: 121 case iOS: 122 case WatchOS: 123 return false; 124 case GCC: 125 case GNUstep: 126 case ObjFW: 127 return true; 128 } 129 llvm_unreachable("bad kind"); 130 } 131 132 /// \brief Is this runtime basically of the NeXT family of runtimes? isNeXTFamily()133 bool isNeXTFamily() const { 134 // For now, this is just the inverse of isGNUFamily(), but that's 135 // not inherently true. 136 return !isGNUFamily(); 137 } 138 139 /// \brief Does this runtime allow ARC at all? allowsARC()140 bool allowsARC() const { 141 switch (getKind()) { 142 case FragileMacOSX: 143 // No stub library for the fragile runtime. 144 return getVersion() >= VersionTuple(10, 7); 145 case MacOSX: return true; 146 case iOS: return true; 147 case WatchOS: return true; 148 case GCC: return false; 149 case GNUstep: return true; 150 case ObjFW: return true; 151 } 152 llvm_unreachable("bad kind"); 153 } 154 155 /// \brief Does this runtime natively provide the ARC entrypoints? 156 /// 157 /// ARC cannot be directly supported on a platform that does not provide 158 /// these entrypoints, although it may be supportable via a stub 159 /// library. hasNativeARC()160 bool hasNativeARC() const { 161 switch (getKind()) { 162 case FragileMacOSX: return getVersion() >= VersionTuple(10, 7); 163 case MacOSX: return getVersion() >= VersionTuple(10, 7); 164 case iOS: return getVersion() >= VersionTuple(5); 165 case WatchOS: return true; 166 167 case GCC: return false; 168 case GNUstep: return getVersion() >= VersionTuple(1, 6); 169 case ObjFW: return true; 170 } 171 llvm_unreachable("bad kind"); 172 } 173 174 /// \brief Does this runtime supports optimized setter entrypoints? hasOptimizedSetter()175 bool hasOptimizedSetter() const { 176 switch (getKind()) { 177 case MacOSX: 178 return getVersion() >= VersionTuple(10, 8); 179 case iOS: 180 return (getVersion() >= VersionTuple(6)); 181 case WatchOS: 182 return true; 183 case GNUstep: 184 return getVersion() >= VersionTuple(1, 7); 185 186 default: 187 return false; 188 } 189 } 190 191 /// Does this runtime allow the use of __weak? allowsWeak()192 bool allowsWeak() const { 193 return hasNativeWeak(); 194 } 195 196 /// \brief Does this runtime natively provide ARC-compliant 'weak' 197 /// entrypoints? hasNativeWeak()198 bool hasNativeWeak() const { 199 // Right now, this is always equivalent to whether the runtime 200 // natively supports ARC decision. 201 return hasNativeARC(); 202 } 203 204 /// \brief Does this runtime directly support the subscripting methods? 205 /// 206 /// This is really a property of the library, not the runtime. hasSubscripting()207 bool hasSubscripting() const { 208 switch (getKind()) { 209 case FragileMacOSX: return false; 210 case MacOSX: return getVersion() >= VersionTuple(10, 8); 211 case iOS: return getVersion() >= VersionTuple(6); 212 case WatchOS: return true; 213 214 // This is really a lie, because some implementations and versions 215 // of the runtime do not support ARC. Probably -fgnu-runtime 216 // should imply a "maximal" runtime or something? 217 case GCC: return true; 218 case GNUstep: return true; 219 case ObjFW: return true; 220 } 221 llvm_unreachable("bad kind"); 222 } 223 224 /// \brief Does this runtime allow sizeof or alignof on object types? allowsSizeofAlignof()225 bool allowsSizeofAlignof() const { 226 return isFragile(); 227 } 228 229 /// \brief Does this runtime allow pointer arithmetic on objects? 230 /// 231 /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic() 232 /// yields true) []. allowsPointerArithmetic()233 bool allowsPointerArithmetic() const { 234 switch (getKind()) { 235 case FragileMacOSX: 236 case GCC: 237 return true; 238 case MacOSX: 239 case iOS: 240 case WatchOS: 241 case GNUstep: 242 case ObjFW: 243 return false; 244 } 245 llvm_unreachable("bad kind"); 246 } 247 248 /// \brief Is subscripting pointer arithmetic? isSubscriptPointerArithmetic()249 bool isSubscriptPointerArithmetic() const { 250 return allowsPointerArithmetic(); 251 } 252 253 /// \brief Does this runtime provide an objc_terminate function? 254 /// 255 /// This is used in handlers for exceptions during the unwind process; 256 /// without it, abort() must be used in pure ObjC files. hasTerminate()257 bool hasTerminate() const { 258 switch (getKind()) { 259 case FragileMacOSX: return getVersion() >= VersionTuple(10, 8); 260 case MacOSX: return getVersion() >= VersionTuple(10, 8); 261 case iOS: return getVersion() >= VersionTuple(5); 262 case WatchOS: return true; 263 case GCC: return false; 264 case GNUstep: return false; 265 case ObjFW: return false; 266 } 267 llvm_unreachable("bad kind"); 268 } 269 270 /// \brief Does this runtime support weakly importing classes? hasWeakClassImport()271 bool hasWeakClassImport() const { 272 switch (getKind()) { 273 case MacOSX: return true; 274 case iOS: return true; 275 case WatchOS: return true; 276 case FragileMacOSX: return false; 277 case GCC: return true; 278 case GNUstep: return true; 279 case ObjFW: return true; 280 } 281 llvm_unreachable("bad kind"); 282 } 283 284 /// \brief Does this runtime use zero-cost exceptions? hasUnwindExceptions()285 bool hasUnwindExceptions() const { 286 switch (getKind()) { 287 case MacOSX: return true; 288 case iOS: return true; 289 case WatchOS: return true; 290 case FragileMacOSX: return false; 291 case GCC: return true; 292 case GNUstep: return true; 293 case ObjFW: return true; 294 } 295 llvm_unreachable("bad kind"); 296 } 297 hasAtomicCopyHelper()298 bool hasAtomicCopyHelper() const { 299 switch (getKind()) { 300 case FragileMacOSX: 301 case MacOSX: 302 case iOS: 303 case WatchOS: 304 return true; 305 case GNUstep: 306 return getVersion() >= VersionTuple(1, 7); 307 default: return false; 308 } 309 } 310 311 /// Is objc_unsafeClaimAutoreleasedReturnValue available? hasARCUnsafeClaimAutoreleasedReturnValue()312 bool hasARCUnsafeClaimAutoreleasedReturnValue() const { 313 switch (getKind()) { 314 case MacOSX: 315 return getVersion() >= VersionTuple(10, 11); 316 case iOS: 317 return getVersion() >= VersionTuple(9); 318 case WatchOS: 319 return getVersion() >= VersionTuple(2); 320 case GNUstep: 321 return false; 322 323 default: 324 return false; 325 } 326 } 327 328 /// \brief Try to parse an Objective-C runtime specification from the given 329 /// string. 330 /// 331 /// \return true on error. 332 bool tryParse(StringRef input); 333 334 std::string getAsString() const; 335 336 friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) { 337 return left.getKind() == right.getKind() && 338 left.getVersion() == right.getVersion(); 339 } 340 341 friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) { 342 return !(left == right); 343 } 344 }; 345 346 raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value); 347 348 } // end namespace clang 349 350 #endif 351