|
| 1 | +//===--- GenericContext.h - ABI for generic signatures ----------*- C++ -*-===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | +// |
| 13 | +// This file describes runtime metadata structures for representing |
| 14 | +// generic signatures. |
| 15 | +// |
| 16 | +//===----------------------------------------------------------------------===// |
| 17 | + |
| 18 | +#ifndef SWIFT_ABI_GENERICCONTEXT_H |
| 19 | +#define SWIFT_ABI_GENERICCONTEXT_H |
| 20 | + |
| 21 | +#include "swift/ABI/TargetLayout.h" |
| 22 | +#include "swift/ABI/MetadataValues.h" |
| 23 | +#include "swift/ABI/MetadataRef.h" |
| 24 | +#include "swift/ABI/TrailingObjects.h" |
| 25 | +#include "swift/Demangling/Demangle.h" |
| 26 | + |
| 27 | +namespace swift { |
| 28 | +template <typename Runtime> |
| 29 | +struct TargetProtocolConformanceDescriptor; |
| 30 | +template <typename Runtime> |
| 31 | +struct TargetGenericContext; |
| 32 | + |
| 33 | +template <typename Runtime> |
| 34 | +struct TargetGenericContextDescriptorHeader { |
| 35 | + /// The number of (source-written) generic parameters, and thus |
| 36 | + /// the number of GenericParamDescriptors associated with this |
| 37 | + /// context. The parameter descriptors appear in the order in |
| 38 | + /// which they were given in the source. |
| 39 | + /// |
| 40 | + /// A GenericParamDescriptor corresponds to a type metadata pointer |
| 41 | + /// in the arguments layout when isKeyArgument() is true. |
| 42 | + /// isKeyArgument() will be false if the parameter has been unified |
| 43 | + /// unified with a different parameter or an associated type. |
| 44 | + uint16_t NumParams; |
| 45 | + |
| 46 | + /// The number of GenericRequirementDescriptors in this generic |
| 47 | + /// signature. |
| 48 | + /// |
| 49 | + /// A GenericRequirementDescriptor of kind Protocol corresponds |
| 50 | + /// to a witness table pointer in the arguments layout when |
| 51 | + /// isKeyArgument() is true. isKeyArgument() will be false if |
| 52 | + /// the protocol is an Objective-C protocol. (Unlike generic |
| 53 | + /// parameters, redundant conformance requirements can simply be |
| 54 | + /// eliminated, and so that case is not impossible.) |
| 55 | + uint16_t NumRequirements; |
| 56 | + |
| 57 | + /// The size of the "key" area of the argument layout, in words. |
| 58 | + /// Key arguments include generic parameters and conformance |
| 59 | + /// requirements which are part of the identity of the context. |
| 60 | + /// |
| 61 | + /// The key area of the argument layout considers of a sequence |
| 62 | + /// of type metadata pointers (in the same order as the parameter |
| 63 | + /// descriptors, for those parameters which satisfy hasKeyArgument()) |
| 64 | + /// followed by a sequence of witness table pointers (in the same |
| 65 | + /// order as the requirements, for those requirements which satisfy |
| 66 | + /// hasKeyArgument()). |
| 67 | + uint16_t NumKeyArguments; |
| 68 | + |
| 69 | + /// In principle, the size of the "extra" area of the argument |
| 70 | + /// layout, in words. The idea was that extra arguments would |
| 71 | + /// include generic parameters and conformances that are not part |
| 72 | + /// of the identity of the context; however, it's unclear why we |
| 73 | + /// would ever want such a thing. As a result, this section is |
| 74 | + /// unused, and this field is always zero. It can be repurposed |
| 75 | + /// as long as it remains zero in code which must be compatible |
| 76 | + /// with existing Swift runtimes. |
| 77 | + uint16_t NumExtraArguments; |
| 78 | + |
| 79 | + uint32_t getNumArguments() const { |
| 80 | + return NumKeyArguments + NumExtraArguments; |
| 81 | + } |
| 82 | + |
| 83 | + /// Return the total size of the argument layout, in words. |
| 84 | + /// The alignment of the argument layout is the word alignment. |
| 85 | + uint32_t getArgumentLayoutSizeInWords() const { |
| 86 | + return getNumArguments(); |
| 87 | + } |
| 88 | + |
| 89 | + bool hasArguments() const { |
| 90 | + return getNumArguments() > 0; |
| 91 | + } |
| 92 | +}; |
| 93 | +using GenericContextDescriptorHeader = |
| 94 | + TargetGenericContextDescriptorHeader<InProcess>; |
| 95 | + |
| 96 | +template<typename Runtime> |
| 97 | +class TargetGenericRequirementDescriptor { |
| 98 | +public: |
| 99 | + GenericRequirementFlags Flags; |
| 100 | + |
| 101 | + /// The type that's constrained, described as a mangled name. |
| 102 | + RelativeDirectPointer<const char, /*nullable*/ false> Param; |
| 103 | + |
| 104 | + union { |
| 105 | + /// A mangled representation of the same-type or base class the param is |
| 106 | + /// constrained to. |
| 107 | + /// |
| 108 | + /// Only valid if the requirement has SameType or BaseClass kind. |
| 109 | + RelativeDirectPointer<const char, /*nullable*/ false> Type; |
| 110 | + |
| 111 | + /// The protocol the param is constrained to. |
| 112 | + /// |
| 113 | + /// Only valid if the requirement has Protocol kind. |
| 114 | + RelativeTargetProtocolDescriptorPointer<Runtime> Protocol; |
| 115 | + |
| 116 | + /// The conformance the param is constrained to use. |
| 117 | + /// |
| 118 | + /// Only valid if the requirement has SameConformance kind. |
| 119 | + RelativeIndirectablePointer<TargetProtocolConformanceDescriptor<Runtime>, |
| 120 | + /*nullable*/ false> Conformance; |
| 121 | + |
| 122 | + /// The kind of layout constraint. |
| 123 | + /// |
| 124 | + /// Only valid if the requirement has Layout kind. |
| 125 | + GenericRequirementLayoutKind Layout; |
| 126 | + }; |
| 127 | + |
| 128 | + constexpr GenericRequirementFlags getFlags() const { |
| 129 | + return Flags; |
| 130 | + } |
| 131 | + |
| 132 | + constexpr GenericRequirementKind getKind() const { |
| 133 | + return getFlags().getKind(); |
| 134 | + } |
| 135 | + |
| 136 | + /// Retrieve the generic parameter that is the subject of this requirement, |
| 137 | + /// as a mangled type name. |
| 138 | + llvm::StringRef getParam() const { |
| 139 | + return swift::Demangle::makeSymbolicMangledNameStringRef(Param.get()); |
| 140 | + } |
| 141 | + |
| 142 | + /// Retrieve the protocol for a Protocol requirement. |
| 143 | + TargetProtocolDescriptorRef<Runtime> getProtocol() const { |
| 144 | + assert(getKind() == GenericRequirementKind::Protocol); |
| 145 | + return Protocol; |
| 146 | + } |
| 147 | + |
| 148 | + /// Retrieve the right-hand type for a SameType or BaseClass requirement. |
| 149 | + llvm::StringRef getMangledTypeName() const { |
| 150 | + assert(getKind() == GenericRequirementKind::SameType || |
| 151 | + getKind() == GenericRequirementKind::BaseClass); |
| 152 | + return swift::Demangle::makeSymbolicMangledNameStringRef(Type.get()); |
| 153 | + } |
| 154 | + |
| 155 | + /// Retrieve the protocol conformance record for a SameConformance |
| 156 | + /// requirement. |
| 157 | + const TargetProtocolConformanceDescriptor<Runtime> *getConformance() const { |
| 158 | + assert(getKind() == GenericRequirementKind::SameConformance); |
| 159 | + return Conformance; |
| 160 | + } |
| 161 | + |
| 162 | + /// Retrieve the layout constraint. |
| 163 | + GenericRequirementLayoutKind getLayout() const { |
| 164 | + assert(getKind() == GenericRequirementKind::Layout); |
| 165 | + return Layout; |
| 166 | + } |
| 167 | + |
| 168 | + /// Determine whether this generic requirement has a known kind. |
| 169 | + /// |
| 170 | + /// \returns \c false for any future generic requirement kinds. |
| 171 | + bool hasKnownKind() const { |
| 172 | + switch (getKind()) { |
| 173 | + case GenericRequirementKind::BaseClass: |
| 174 | + case GenericRequirementKind::Layout: |
| 175 | + case GenericRequirementKind::Protocol: |
| 176 | + case GenericRequirementKind::SameConformance: |
| 177 | + case GenericRequirementKind::SameType: |
| 178 | + return true; |
| 179 | + } |
| 180 | + |
| 181 | + return false; |
| 182 | + } |
| 183 | +}; |
| 184 | +using GenericRequirementDescriptor = |
| 185 | + TargetGenericRequirementDescriptor<InProcess>; |
| 186 | + |
| 187 | +template<typename Runtime> |
| 188 | +class TargetGenericEnvironment |
| 189 | + : public swift::ABI::TrailingObjects<TargetGenericEnvironment<Runtime>, |
| 190 | + uint16_t, GenericParamDescriptor, |
| 191 | + TargetGenericRequirementDescriptor<Runtime>> { |
| 192 | + using GenericRequirementDescriptor = |
| 193 | + TargetGenericRequirementDescriptor<Runtime>; |
| 194 | + using TrailingObjects = |
| 195 | + swift::ABI::TrailingObjects<TargetGenericEnvironment<Runtime>, |
| 196 | + uint16_t, GenericParamDescriptor, GenericRequirementDescriptor>; |
| 197 | + friend TrailingObjects; |
| 198 | + |
| 199 | +#if !defined(_MSC_VER) || _MSC_VER >= 1920 |
| 200 | + template<typename T> |
| 201 | + using OverloadToken = typename TrailingObjects::template OverloadToken<T>; |
| 202 | +#else |
| 203 | +// MSVC 2017 trips parsing an using of an using, of a variadic template |
| 204 | +#define OverloadToken typename TrailingObjects::template OverloadToken |
| 205 | +#endif |
| 206 | + |
| 207 | + size_t numTrailingObjects(OverloadToken<uint16_t>) const { |
| 208 | + return Flags.getNumGenericParameterLevels(); |
| 209 | + } |
| 210 | + |
| 211 | + size_t numTrailingObjects(OverloadToken<GenericParamDescriptor>) const { |
| 212 | + return getGenericParameterCounts().back(); |
| 213 | + } |
| 214 | + |
| 215 | + size_t numTrailingObjects(OverloadToken<GenericRequirementDescriptor>) const { |
| 216 | + return Flags.getNumGenericRequirements(); |
| 217 | + } |
| 218 | + |
| 219 | +#if defined(_MSC_VER) && _MSC_VER < 1920 |
| 220 | +#undef OverloadToken |
| 221 | +#endif |
| 222 | + |
| 223 | + GenericEnvironmentFlags Flags; |
| 224 | + |
| 225 | +public: |
| 226 | + /// Retrieve the cumulative generic parameter counts at each level of genericity. |
| 227 | + llvm::ArrayRef<uint16_t> getGenericParameterCounts() const { |
| 228 | + return llvm::makeArrayRef(this->template getTrailingObjects<uint16_t>(), |
| 229 | + Flags.getNumGenericParameterLevels()); |
| 230 | + } |
| 231 | + |
| 232 | + /// Retrieve the generic parameters descriptors. |
| 233 | + llvm::ArrayRef<GenericParamDescriptor> getGenericParameters() const { |
| 234 | + return llvm::makeArrayRef( |
| 235 | + this->template getTrailingObjects<GenericParamDescriptor>(), |
| 236 | + getGenericParameterCounts().back()); |
| 237 | + } |
| 238 | + |
| 239 | + /// Retrieve the generic requirements. |
| 240 | + llvm::ArrayRef<GenericRequirementDescriptor> getGenericRequirements() const { |
| 241 | + return llvm::makeArrayRef( |
| 242 | + this->template getTrailingObjects<GenericRequirementDescriptor>(), |
| 243 | + Flags.getNumGenericRequirements()); |
| 244 | + } |
| 245 | +}; |
| 246 | + |
| 247 | +using GenericEnvironmentDescriptor = TargetGenericEnvironment<InProcess>; |
| 248 | + |
| 249 | +/// CRTP class for a context descriptor that includes trailing generic |
| 250 | +/// context description. |
| 251 | +template<class Self, |
| 252 | + template <typename> class TargetGenericContextHeaderType = |
| 253 | + TargetGenericContextDescriptorHeader, |
| 254 | + typename... FollowingTrailingObjects> |
| 255 | +class TrailingGenericContextObjects; |
| 256 | + |
| 257 | +// This oddity with partial specialization is necessary to get |
| 258 | +// reasonable-looking code while also working around various kinds of |
| 259 | +// compiler bad behavior with injected class names. |
| 260 | +template<class Runtime, |
| 261 | + template <typename> class TargetSelf, |
| 262 | + template <typename> class TargetGenericContextHeaderType, |
| 263 | + typename... FollowingTrailingObjects> |
| 264 | +class TrailingGenericContextObjects<TargetSelf<Runtime>, |
| 265 | + TargetGenericContextHeaderType, |
| 266 | + FollowingTrailingObjects...> : |
| 267 | + protected swift::ABI::TrailingObjects<TargetSelf<Runtime>, |
| 268 | + TargetGenericContextHeaderType<Runtime>, |
| 269 | + GenericParamDescriptor, |
| 270 | + TargetGenericRequirementDescriptor<Runtime>, |
| 271 | + FollowingTrailingObjects...> |
| 272 | +{ |
| 273 | +protected: |
| 274 | + using Self = TargetSelf<Runtime>; |
| 275 | + using GenericContextHeaderType = TargetGenericContextHeaderType<Runtime>; |
| 276 | + using GenericRequirementDescriptor = |
| 277 | + TargetGenericRequirementDescriptor<Runtime>; |
| 278 | + |
| 279 | + using TrailingObjects = swift::ABI::TrailingObjects<Self, |
| 280 | + GenericContextHeaderType, |
| 281 | + GenericParamDescriptor, |
| 282 | + GenericRequirementDescriptor, |
| 283 | + FollowingTrailingObjects...>; |
| 284 | + friend TrailingObjects; |
| 285 | + |
| 286 | +#if !defined(_MSC_VER) || _MSC_VER >= 1920 |
| 287 | + template<typename T> |
| 288 | + using OverloadToken = typename TrailingObjects::template OverloadToken<T>; |
| 289 | +#else |
| 290 | +// MSVC 2017 trips parsing an using of an using, of a variadic template |
| 291 | +#define OverloadToken typename TrailingObjects::template OverloadToken |
| 292 | +#endif |
| 293 | + |
| 294 | + const Self *asSelf() const { |
| 295 | + return static_cast<const Self *>(this); |
| 296 | + } |
| 297 | +public: |
| 298 | + using StoredSize = typename Runtime::StoredSize; |
| 299 | + using StoredPointer = typename Runtime::StoredPointer; |
| 300 | + |
| 301 | + const GenericContextHeaderType &getFullGenericContextHeader() const { |
| 302 | + assert(asSelf()->isGeneric()); |
| 303 | + return *this->template getTrailingObjects<GenericContextHeaderType>(); |
| 304 | + } |
| 305 | + |
| 306 | + const TargetGenericContextDescriptorHeader<Runtime> & |
| 307 | + getGenericContextHeader() const { |
| 308 | + /// HeaderType ought to be convertible to GenericContextDescriptorHeader. |
| 309 | + return getFullGenericContextHeader(); |
| 310 | + } |
| 311 | + |
| 312 | + const TargetGenericContext<Runtime> *getGenericContext() const { |
| 313 | + if (!asSelf()->isGeneric()) |
| 314 | + return nullptr; |
| 315 | + // The generic context header should always be immediately followed in |
| 316 | + // memory by trailing parameter and requirement descriptors. |
| 317 | + auto *header = reinterpret_cast<const char *>(&getGenericContextHeader()); |
| 318 | + return reinterpret_cast<const TargetGenericContext<Runtime> *>( |
| 319 | + header - sizeof(TargetGenericContext<Runtime>)); |
| 320 | + } |
| 321 | + |
| 322 | + llvm::ArrayRef<GenericParamDescriptor> getGenericParams() const { |
| 323 | + if (!asSelf()->isGeneric()) |
| 324 | + return {}; |
| 325 | + |
| 326 | + return {this->template getTrailingObjects<GenericParamDescriptor>(), |
| 327 | + getGenericContextHeader().NumParams}; |
| 328 | + } |
| 329 | + |
| 330 | + llvm::ArrayRef<GenericRequirementDescriptor> getGenericRequirements() const { |
| 331 | + if (!asSelf()->isGeneric()) |
| 332 | + return {}; |
| 333 | + return {this->template getTrailingObjects<GenericRequirementDescriptor>(), |
| 334 | + getGenericContextHeader().NumRequirements}; |
| 335 | + } |
| 336 | + |
| 337 | + /// Return the amount of space that the generic arguments take up in |
| 338 | + /// metadata of this type. |
| 339 | + StoredSize getGenericArgumentsStorageSize() const { |
| 340 | + return StoredSize(getGenericContextHeader().getNumArguments()) |
| 341 | + * sizeof(StoredPointer); |
| 342 | + } |
| 343 | + |
| 344 | +protected: |
| 345 | + size_t numTrailingObjects(OverloadToken<GenericContextHeaderType>) const { |
| 346 | + return asSelf()->isGeneric() ? 1 : 0; |
| 347 | + } |
| 348 | + |
| 349 | + size_t numTrailingObjects(OverloadToken<GenericParamDescriptor>) const { |
| 350 | + return asSelf()->isGeneric() ? getGenericContextHeader().NumParams : 0; |
| 351 | + } |
| 352 | + |
| 353 | + size_t numTrailingObjects(OverloadToken<GenericRequirementDescriptor>) const { |
| 354 | + return asSelf()->isGeneric() ? getGenericContextHeader().NumRequirements : 0; |
| 355 | + } |
| 356 | + |
| 357 | +#if defined(_MSC_VER) && _MSC_VER < 1920 |
| 358 | +#undef OverloadToken |
| 359 | +#endif |
| 360 | + |
| 361 | +}; |
| 362 | + |
| 363 | +/// Description of a generic context. |
| 364 | +template<typename Runtime> |
| 365 | +struct TargetGenericContext final |
| 366 | + : TrailingGenericContextObjects<TargetGenericContext<Runtime>, |
| 367 | + TargetGenericContextDescriptorHeader> |
| 368 | +{ |
| 369 | + // This struct is supposed to be empty, but TrailingObjects respects the |
| 370 | + // unique-address-per-object C++ rule, so even if this type is empty, the |
| 371 | + // trailing objects will come after one byte of padding. This dummy field |
| 372 | + // takes up space to make the offset of the trailing objects portable. |
| 373 | + unsigned _dummy; |
| 374 | + |
| 375 | + bool isGeneric() const { return true; } |
| 376 | +}; |
| 377 | + |
| 378 | +} // end namespace swift |
| 379 | + |
| 380 | +#endif |
0 commit comments