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 true; 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 } 102 else if ((getKind() == MacOSX) && isNonFragile() && 103 (getVersion() >= VersionTuple(10, 0)) && 104 (getVersion() < VersionTuple(10, 6))) 105 return Arch != llvm::Triple::x86_64; 106 // Except for deployment target of 10.5 or less, 107 // Mac runtimes use legacy dispatch everywhere now. 108 return true; 109 } 110 111 /// \brief Is this runtime basically of the GNU family of runtimes? isGNUFamily()112 bool isGNUFamily() const { 113 switch (getKind()) { 114 case FragileMacOSX: 115 case MacOSX: 116 case iOS: 117 return false; 118 case GCC: 119 case GNUstep: 120 case ObjFW: 121 return true; 122 } 123 llvm_unreachable("bad kind"); 124 } 125 126 /// \brief Is this runtime basically of the NeXT family of runtimes? isNeXTFamily()127 bool isNeXTFamily() const { 128 // For now, this is just the inverse of isGNUFamily(), but that's 129 // not inherently true. 130 return !isGNUFamily(); 131 } 132 133 /// \brief Does this runtime allow ARC at all? allowsARC()134 bool allowsARC() const { 135 switch (getKind()) { 136 case FragileMacOSX: return false; 137 case MacOSX: return true; 138 case iOS: return true; 139 case GCC: return false; 140 case GNUstep: return true; 141 case ObjFW: return true; 142 } 143 llvm_unreachable("bad kind"); 144 } 145 146 /// \brief Does this runtime natively provide the ARC entrypoints? 147 /// 148 /// ARC cannot be directly supported on a platform that does not provide 149 /// these entrypoints, although it may be supportable via a stub 150 /// library. hasNativeARC()151 bool hasNativeARC() const { 152 switch (getKind()) { 153 case FragileMacOSX: return false; 154 case MacOSX: return getVersion() >= VersionTuple(10, 7); 155 case iOS: return getVersion() >= VersionTuple(5); 156 157 case GCC: return false; 158 case GNUstep: return getVersion() >= VersionTuple(1, 6); 159 case ObjFW: return true; 160 } 161 llvm_unreachable("bad kind"); 162 } 163 164 /// \brief Does this runtime supports optimized setter entrypoints? hasOptimizedSetter()165 bool hasOptimizedSetter() const { 166 switch (getKind()) { 167 case MacOSX: 168 return getVersion() >= VersionTuple(10, 8); 169 case iOS: 170 return (getVersion() >= VersionTuple(6)); 171 case GNUstep: 172 return getVersion() >= VersionTuple(1, 7); 173 174 default: 175 return false; 176 } 177 } 178 179 /// Does this runtime allow the use of __weak? allowsWeak()180 bool allowsWeak() const { 181 return hasNativeWeak(); 182 } 183 184 /// \brief Does this runtime natively provide ARC-compliant 'weak' 185 /// entrypoints? hasNativeWeak()186 bool hasNativeWeak() const { 187 // Right now, this is always equivalent to whether the runtime 188 // natively supports ARC decision. 189 return hasNativeARC(); 190 } 191 192 /// \brief Does this runtime directly support the subscripting methods? 193 /// 194 /// This is really a property of the library, not the runtime. hasSubscripting()195 bool hasSubscripting() const { 196 switch (getKind()) { 197 case FragileMacOSX: return false; 198 case MacOSX: return getVersion() >= VersionTuple(10, 8); 199 case iOS: return getVersion() >= VersionTuple(6); 200 201 // This is really a lie, because some implementations and versions 202 // of the runtime do not support ARC. Probably -fgnu-runtime 203 // should imply a "maximal" runtime or something? 204 case GCC: return true; 205 case GNUstep: return true; 206 case ObjFW: return true; 207 } 208 llvm_unreachable("bad kind"); 209 } 210 211 /// \brief Does this runtime allow sizeof or alignof on object types? allowsSizeofAlignof()212 bool allowsSizeofAlignof() const { 213 return isFragile(); 214 } 215 216 /// \brief Does this runtime allow pointer arithmetic on objects? 217 /// 218 /// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic() 219 /// yields true) []. allowsPointerArithmetic()220 bool allowsPointerArithmetic() const { 221 switch (getKind()) { 222 case FragileMacOSX: 223 case GCC: 224 return true; 225 case MacOSX: 226 case iOS: 227 case GNUstep: 228 case ObjFW: 229 return false; 230 } 231 llvm_unreachable("bad kind"); 232 } 233 234 /// \brief Is subscripting pointer arithmetic? isSubscriptPointerArithmetic()235 bool isSubscriptPointerArithmetic() const { 236 return allowsPointerArithmetic(); 237 } 238 239 /// \brief Does this runtime provide an objc_terminate function? 240 /// 241 /// This is used in handlers for exceptions during the unwind process; 242 /// without it, abort() must be used in pure ObjC files. hasTerminate()243 bool hasTerminate() const { 244 switch (getKind()) { 245 case FragileMacOSX: return getVersion() >= VersionTuple(10, 8); 246 case MacOSX: return getVersion() >= VersionTuple(10, 8); 247 case iOS: return getVersion() >= VersionTuple(5); 248 case GCC: return false; 249 case GNUstep: return false; 250 case ObjFW: return false; 251 } 252 llvm_unreachable("bad kind"); 253 } 254 255 /// \brief Does this runtime support weakly importing classes? hasWeakClassImport()256 bool hasWeakClassImport() const { 257 switch (getKind()) { 258 case MacOSX: return true; 259 case iOS: return true; 260 case FragileMacOSX: return false; 261 case GCC: return true; 262 case GNUstep: return true; 263 case ObjFW: return true; 264 } 265 llvm_unreachable("bad kind"); 266 } 267 268 /// \brief Does this runtime use zero-cost exceptions? hasUnwindExceptions()269 bool hasUnwindExceptions() const { 270 switch (getKind()) { 271 case MacOSX: return true; 272 case iOS: return true; 273 case FragileMacOSX: return false; 274 case GCC: return true; 275 case GNUstep: return true; 276 case ObjFW: return true; 277 } 278 llvm_unreachable("bad kind"); 279 } 280 hasAtomicCopyHelper()281 bool hasAtomicCopyHelper() const { 282 switch (getKind()) { 283 case FragileMacOSX: 284 case MacOSX: 285 case iOS: 286 return true; 287 case GNUstep: 288 return getVersion() >= VersionTuple(1, 7); 289 default: return false; 290 } 291 } 292 293 /// \brief Try to parse an Objective-C runtime specification from the given 294 /// string. 295 /// 296 /// \return true on error. 297 bool tryParse(StringRef input); 298 299 std::string getAsString() const; 300 301 friend bool operator==(const ObjCRuntime &left, const ObjCRuntime &right) { 302 return left.getKind() == right.getKind() && 303 left.getVersion() == right.getVersion(); 304 } 305 306 friend bool operator!=(const ObjCRuntime &left, const ObjCRuntime &right) { 307 return !(left == right); 308 } 309 }; 310 311 raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value); 312 313 } // end namespace clang 314 315 #endif 316