//===--- ExistentialMetadataImpl.h - Existential metadata ------*- C++ -*--===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // Declarations used to implement value witnesses for Swift // existential types. // //===----------------------------------------------------------------------===// #ifndef SWIFT_RUNTIME_EXISTENTIALMETADATAIMPL_H #define SWIFT_RUNTIME_EXISTENTIALMETADATAIMPL_H #include "MetadataImpl.h" namespace swift { namespace metadataimpl { /// A common base class for opaque-existential and class-existential boxes. template struct LLVM_LIBRARY_VISIBILITY ExistentialBoxBase { template static void destroyArray(Container *array, size_t n, A... args) { size_t stride = Container::getContainerStride(args...); char *bytes = (char*)array; while (n--) { Impl::destroy((Container*)bytes, args...); bytes += stride; } } template static Container *initializeArrayWithCopy(Container *dest, Container *src, size_t n, A... args) { size_t stride = Container::getContainerStride(args...); char *destBytes = (char*)dest, *srcBytes = (char*)src; while (n--) { Impl::initializeWithCopy((Container*)destBytes, (Container*)srcBytes, args...); destBytes += stride; srcBytes += stride; } return dest; } template static Container *initializeArrayWithTakeFrontToBack(Container *dest, Container *src, size_t n, A... args) { size_t stride = Container::getContainerStride(args...); char *destBytes = (char*)dest, *srcBytes = (char*)src; while (n--) { Impl::initializeWithTake((Container*)destBytes, (Container*)srcBytes, args...); destBytes += stride; srcBytes += stride; } return dest; } template static Container *initializeArrayWithTakeBackToFront(Container *dest, Container *src, size_t n, A... args) { size_t stride = Container::getContainerStride(args...); char *destBytes = (char*)dest + n * stride, *srcBytes = (char*)src + n * stride; while (n--) { destBytes -= stride; srcBytes -= stride; Impl::initializeWithTake((Container*)destBytes, (Container*)srcBytes, args...); } return dest; } }; /// A common base class for fixed and non-fixed opaque-existential box /// implementations. struct LLVM_LIBRARY_VISIBILITY OpaqueExistentialBoxBase : ExistentialBoxBase { template static void destroy(Container *value, A... args) { value->getType()->vw_destroyBuffer(value->getBuffer(args...)); } template static Container *initializeWithCopy(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); src->getType()->vw_initializeBufferWithCopyOfBuffer(dest->getBuffer(args...), src->getBuffer(args...)); return dest; } template static Container *initializeWithTake(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); src->getType()->vw_initializeBufferWithTakeOfBuffer(dest->getBuffer(args...), src->getBuffer(args...)); return dest; } template static Container *assignWithCopy(Container *dest, Container *src, A... args) { auto srcType = src->getType(); auto destType = dest->getType(); if (srcType == destType) { OpaqueValue *srcValue = srcType->vw_projectBuffer(src->getBuffer(args...)); OpaqueValue *destValue = srcType->vw_projectBuffer(dest->getBuffer(args...)); srcType->vw_assignWithCopy(destValue, srcValue); return dest; } else { destType->vw_destroyBuffer(dest->getBuffer(args...)); return initializeWithCopy(dest, src, args...); } } template static Container *assignWithTake(Container *dest, Container *src, A... args) { auto srcType = src->getType(); auto destType = dest->getType(); if (srcType == destType) { OpaqueValue *srcValue = srcType->vw_projectBuffer(src->getBuffer(args...)); OpaqueValue *destValue = srcType->vw_projectBuffer(dest->getBuffer(args...)); srcType->vw_assignWithTake(destValue, srcValue); return dest; } else { destType->vw_destroyBuffer(dest->getBuffer(args...)); return initializeWithTake(dest, src, args...); } } }; /// The basic layout of an opaque existential with a fixed number of /// witness tables. Note that the WitnessTables field is accessed via /// spooky action from Header. template struct LLVM_LIBRARY_VISIBILITY FixedOpaqueExistentialContainer { OpaqueExistentialContainer Header; const void *WitnessTables[NumWitnessTables]; }; // We need to be able to instantiate for NumWitnessTables==0, which // requires an explicit specialization. template <> struct FixedOpaqueExistentialContainer<0> { OpaqueExistentialContainer Header; }; /// A box implementation class for an opaque existential type with /// a fixed number of witness tables. template struct LLVM_LIBRARY_VISIBILITY OpaqueExistentialBox : OpaqueExistentialBoxBase { struct Container : FixedOpaqueExistentialContainer { const Metadata *getType() const { return this->Header.Type; } ValueBuffer *getBuffer() { return &this->Header.Buffer; } void copyTypeInto(Container *dest) const { this->Header.copyTypeInto(&dest->Header, NumWitnessTables); } static size_t getContainerStride() { return sizeof(Container); } }; using type = Container; static constexpr size_t size = sizeof(Container); static constexpr size_t alignment = alignof(Container); static constexpr size_t stride = sizeof(Container); static constexpr size_t isPOD = false; static constexpr bool isBitwiseTakable = false; static constexpr unsigned numExtraInhabitants = 0; }; /// A non-fixed box implementation class for an opaque existential /// type with a dynamic number of witness tables. struct LLVM_LIBRARY_VISIBILITY NonFixedOpaqueExistentialBox : OpaqueExistentialBoxBase { struct Container { OpaqueExistentialContainer Header; const Metadata *getType() { return Header.Type; } ValueBuffer *getBuffer(const Metadata *self) { return &Header.Buffer; } void copyTypeInto(Container *dest, const Metadata *self) { Header.copyTypeInto(&dest->Header, getNumWitnessTables(self)); } static unsigned getNumWitnessTables(const Metadata *self) { auto castSelf = static_cast(self); return castSelf->Flags.getNumWitnessTables(); } static size_t getAlignment(unsigned numWitnessTables) { return std::max(alignof(void*), alignof(ValueBuffer)); } static size_t getSize(unsigned numWitnessTables) { return sizeof(OpaqueExistentialContainer) + numWitnessTables * sizeof(void*); } static size_t getStride(unsigned numWitnessTables) { return getSize(numWitnessTables); } static size_t getContainerStride(const Metadata *self) { return getStride(getNumWitnessTables(self)); } }; using type = Container; static constexpr unsigned numExtraInhabitants = 0; }; /// A common base class for fixed and non-fixed class-existential box /// implementations. struct LLVM_LIBRARY_VISIBILITY ClassExistentialBoxBase : ExistentialBoxBase { static constexpr unsigned numExtraInhabitants = swift_getHeapObjectExtraInhabitantCount(); template static void destroy(Container *value, A... args) { swift_unknownRelease(*value->getValueSlot()); } template static Container *initializeWithCopy(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); auto newValue = *src->getValueSlot(); *dest->getValueSlot() = newValue; swift_unknownRetain(newValue); return dest; } template static Container *initializeWithTake(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); *dest->getValueSlot() = *src->getValueSlot(); return dest; } template static Container *assignWithCopy(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); auto newValue = *src->getValueSlot(); auto oldValue = *dest->getValueSlot(); *dest->getValueSlot() = newValue; swift_unknownRetain(newValue); swift_unknownRelease(oldValue); return dest; } template static Container *assignWithTake(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); auto newValue = *src->getValueSlot(); auto oldValue = *dest->getValueSlot(); *dest->getValueSlot() = newValue; swift_unknownRelease(oldValue); return dest; } template static void storeExtraInhabitant(Container *dest, int index, A... args) { swift_storeHeapObjectExtraInhabitant((HeapObject**) dest->getValueSlot(), index); } template static int getExtraInhabitantIndex(const Container *src, A... args) { return swift_getHeapObjectExtraInhabitantIndex( (HeapObject* const *) src->getValueSlot()); } }; /// A box implementation class for an existential container with /// a class constraint and a fixed number of protocol witness tables. template struct LLVM_LIBRARY_VISIBILITY ClassExistentialBox : ClassExistentialBoxBase { struct Container { ClassExistentialContainer Header; const void *TypeInfo[NumWitnessTables]; void copyTypeInto(Container *dest) const { for (unsigned i = 0; i != NumWitnessTables; ++i) dest->TypeInfo[i] = TypeInfo[i]; } void **getValueSlot() { return &Header.Value; } void * const *getValueSlot() const { return &Header.Value; } static size_t getContainerStride() { return sizeof(Container); } }; using type = Container; static constexpr size_t size = sizeof(Container); static constexpr size_t alignment = alignof(Container); static constexpr size_t stride = sizeof(Container); static constexpr size_t isPOD = false; static constexpr size_t isBitwiseTakable = true; }; /// A non-fixed box implementation class for an class existential /// type with a dynamic number of witness tables. struct LLVM_LIBRARY_VISIBILITY NonFixedClassExistentialBox : ClassExistentialBoxBase { struct Container { ClassExistentialContainer Header; static unsigned getNumWitnessTables(const Metadata *self) { auto castSelf = static_cast(self); return castSelf->Flags.getNumWitnessTables(); } void copyTypeInto(Container *dest, const Metadata *self) { Header.copyTypeInto(&dest->Header, getNumWitnessTables(self)); } void **getValueSlot() { return &Header.Value; } void * const *getValueSlot() const { return &Header.Value; } static size_t getAlignment(unsigned numWitnessTables) { return alignof(void*); } static size_t getSize(unsigned numWitnessTables) { return sizeof(ClassExistentialContainer) + numWitnessTables * sizeof(void*); } static size_t getStride(unsigned numWitnessTables) { return getSize(numWitnessTables); } static size_t getContainerStride(const Metadata *self) { return getStride(getNumWitnessTables(self)); } }; using type = Container; }; /// A common base class for fixed and non-fixed existential metatype box /// implementations. struct LLVM_LIBRARY_VISIBILITY ExistentialMetatypeBoxBase : ExistentialBoxBase { static constexpr unsigned numExtraInhabitants = swift_getHeapObjectExtraInhabitantCount(); template static void destroy(Container *value, A... args) { } template static Container *initializeWithCopy(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); *dest->getValueSlot() = *src->getValueSlot(); return dest; } template static Container *initializeWithTake(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); *dest->getValueSlot() = *src->getValueSlot(); return dest; } template static Container *assignWithCopy(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); *dest->getValueSlot() = *src->getValueSlot(); return dest; } template static Container *assignWithTake(Container *dest, Container *src, A... args) { src->copyTypeInto(dest, args...); *dest->getValueSlot() = *src->getValueSlot(); return dest; } template static void storeExtraInhabitant(Container *dest, int index, A... args) { swift_storeHeapObjectExtraInhabitant((HeapObject**) dest->getValueSlot(), index); } template static int getExtraInhabitantIndex(const Container *src, A... args) { return swift_getHeapObjectExtraInhabitantIndex( (HeapObject* const *) src->getValueSlot()); } }; /// A box implementation class for an existential metatype container /// with a fixed number of protocol witness tables. template struct LLVM_LIBRARY_VISIBILITY ExistentialMetatypeBox : ExistentialMetatypeBoxBase { struct Container { ExistentialMetatypeContainer Header; const void *TypeInfo[NumWitnessTables]; void copyTypeInto(Container *dest) const { for (unsigned i = 0; i != NumWitnessTables; ++i) dest->TypeInfo[i] = TypeInfo[i]; } const Metadata **getValueSlot() { return &Header.Value; } const Metadata * const *getValueSlot() const { return &Header.Value; } static size_t getContainerStride() { return sizeof(Container); } }; using type = Container; static constexpr size_t size = sizeof(Container); static constexpr size_t alignment = alignof(Container); static constexpr size_t stride = sizeof(Container); static constexpr size_t isPOD = true; static constexpr size_t isBitwiseTakable = true; }; /// A non-fixed box implementation class for an existential metatype /// type with a dynamic number of witness tables. struct LLVM_LIBRARY_VISIBILITY NonFixedExistentialMetatypeBox : ExistentialMetatypeBoxBase { struct Container { ExistentialMetatypeContainer Header; static unsigned getNumWitnessTables(const Metadata *self) { auto castSelf = static_cast(self); return castSelf->Flags.getNumWitnessTables(); } void copyTypeInto(Container *dest, const Metadata *self) { Header.copyTypeInto(&dest->Header, getNumWitnessTables(self)); } const Metadata **getValueSlot() { return &Header.Value; } const Metadata * const *getValueSlot() const { return &Header.Value; } static size_t getAlignment(unsigned numWitnessTables) { return alignof(void*); } static size_t getSize(unsigned numWitnessTables) { return sizeof(ExistentialMetatypeContainer) + numWitnessTables * sizeof(void*); } static size_t getStride(unsigned numWitnessTables) { return getSize(numWitnessTables); } static size_t getContainerStride(const Metadata *self) { return getStride(getNumWitnessTables(self)); } }; using type = Container; }; } // end namespace metadataimpl } // end namespace swift #endif /* SWIFT_RUNTIME_EXISTENTIALMETADATAIMPL_H */