//===--- ValueWitness.h - Enumeration of value witnesses --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the list of witnesses required to attest that a // type is a value type. // //===----------------------------------------------------------------------===// #ifndef SWIFT_IRGEN_VALUEWITNESS_H #define SWIFT_IRGEN_VALUEWITNESS_H namespace swift { namespace irgen { /// The members required to attest that a type is a value type. /// /// Logically, there are three basic data operations we must support /// on arbitrary types: /// - initializing an object by copying another /// - changing an object to be a copy of another /// - destroying an object /// /// As an optimization to permit efficient transfers of data, the /// "copy" operations each have an analogous "take" operation which /// implicitly destroys the source object. /// /// Therefore there are five basic data operations: /// initWithCopy(T*, T*) /// initWithTake(T*, T*) /// assignWithCopy(T*, T*) /// assignWithTake(T*, T*) /// destroy(T*) /// /// As a further optimization, for every T*, there is a related /// operation which replaces that T* with a B*, combinatorially. This /// makes 18 operations, except that some of these operations are /// fairly unlikely and so do not merit optimized entries, due to /// the common code patterns of the two use cases: /// - Existential code usually doesn't work directly with T*s /// because pointers into existential objects are not generally /// reliable. /// - Generic code works with T*s a fair amount, but it usually /// doesn't have to deal with B*s after initialization /// because initialization returns a reliable pointer. /// This leads us to the following conclusions: // - Operations to copy a B* to a T* are very unlikely /// to be used (-4 operations). /// - Assignments involving two B*s are only likely in /// existential code, where we won't have the right /// typing guarantees to use them (-2 operations). /// Furthermore, take-initializing a buffer from a buffer is just a /// memcpy of the buffer (-1), and take-assigning a buffer from a /// buffer is just a destroy and a memcpy (-1). /// /// This leaves us with 12 data operations, to which we add the /// meta-operation 'sizeAndAlign' for a total of 13. enum class ValueWitness : unsigned { #define WANT_ALL_VALUE_WITNESSES #define VALUE_WITNESS(lowerId, upperId) upperId, #define BEGIN_VALUE_WITNESS_RANGE(rangeId, upperId) First_##rangeId = upperId, #define END_VALUE_WITNESS_RANGE(rangeId, upperId) Last_##rangeId = upperId, #include "swift/ABI/ValueWitness.def" }; // The namespaces here are to force the enumerators to be scoped. We don't // use 'enum class' because we want the enumerators to convert freely // to uint64_t. namespace ValueWitnessFlags { enum : uint64_t { AlignmentMask = 0x0FFFF, IsNonPOD = 0x10000, IsNonInline = 0x20000, /// Flags pertaining to enum representation. Enum_FlagMask = 0xC0000, /// If Flags & Enum_FlagMask == Enum_IsOpaque, then the type does not /// support any optimized representation in enums. Enum_IsOpaque = 0x00000, /// If Flags & Enum_FlagMask == Enum_HasExtraInhabitants, then the type /// has "extra inhabitants" of its binary representation which do not form /// valid values of the type, such as null in a class type. The /// ExtraInhabitants value witnesses are present in the value witness table. Enum_HasExtraInhabitants = 0x40000, /// If Flags & Enum_FlagMask == Enum_HasSpareBits, then the type has /// unused bits in its binary representation. This implies /// HasExtraInhabitants. Both the ExtraInhabitants and SpareBits value /// witnesses are present in the value witness table. Enum_HasSpareBits = 0xC0000, IsNonBitwiseTakable = 0x100000, /// If Flags & HasEnumWitnesses, then enum value witnesses are present in /// the value witness table. HasEnumWitnesses = 0x00200000, }; } namespace ExtraInhabitantFlags { enum : uint64_t { NumExtraInhabitantsMask = 0x7FFFFFFFULL, NumSpareBitsMask = 0x0000FFFF00000000ULL, NumSpareBitsShift = 32, SpareBitsShiftMask = 0xFFFF000000000000ULL, SpareBitsShiftShift = 48, }; } enum { NumRequiredValueWitnesses = unsigned(ValueWitness::Last_RequiredValueWitness) + 1, NumRequiredValueWitnessFunctions = unsigned(ValueWitness::Last_RequiredValueWitnessFunction) + 1, MaxNumValueWitnesses = unsigned(ValueWitness::Last_ValueWitness) + 1, MaxNumTypeLayoutWitnesses = unsigned(ValueWitness::Last_TypeLayoutWitness) - unsigned(ValueWitness::First_TypeLayoutWitness) + 1, }; static inline bool isValueWitnessFunction(ValueWitness witness) { #define WANT_ALL_VALUE_WITNESSES 1 #define FUNCTION_VALUE_WITNESS(name, Name, ret, args) \ if (witness == ValueWitness::Name) \ return true; #define DATA_VALUE_WITNESS(name, Name, ty) #include "swift/ABI/ValueWitness.def" return false; } const char *getValueWitnessName(ValueWitness witness); } // end namespace irgen } // end namespace swift #endif