mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* spelling: against Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: algorithmic Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: alignment Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: anything Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: architectural Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: architecture Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: are Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: artificial Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: aside Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: available Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: being Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: bidirectional Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: characters Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: circular Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: compatibility Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: compiled Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: correctly Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: covers Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: declaration Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: dependencies Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: descriptor Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: dictionaries Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: dynamic Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: greater Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: hierarchy Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: immortal Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: initialize Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: initializes Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: iterable Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: message Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: minimum Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: multiple Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: originally Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: simplified Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: sophisticated Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: trivia Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: wasn't Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> Co-authored-by: Josh Soref <jsoref@users.noreply.github.com>
656 lines
22 KiB
C++
656 lines
22 KiB
C++
//===--- ExistentialMetadataImpl.h - Existential metadata -------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Declarations used to implement value witnesses for Swift
|
|
// existential types.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_RUNTIME_EXISTENTIALMETADATAIMPL_H
|
|
#define SWIFT_RUNTIME_EXISTENTIALMETADATAIMPL_H
|
|
|
|
#include "MetadataImpl.h"
|
|
#include "swift/Runtime/ExistentialContainer.h"
|
|
|
|
namespace swift {
|
|
namespace metadataimpl {
|
|
|
|
/// A common base class for opaque-existential and class-existential boxes.
|
|
template <typename Impl> struct SWIFT_LIBRARY_VISIBILITY ExistentialBoxBase {};
|
|
|
|
/// A common base class for fixed and non-fixed opaque-existential box
|
|
/// implementations.
|
|
struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
|
|
: ExistentialBoxBase<OpaqueExistentialBoxBase> {
|
|
template <class Container, class... A>
|
|
static void destroy(Container *value, A... args) {
|
|
auto *type = value->getType();
|
|
auto *vwt = type->getValueWitnesses();
|
|
if (vwt->isValueInline()) {
|
|
// destroy(&valueBuffer)
|
|
type->vw_destroy(
|
|
reinterpret_cast<OpaqueValue *>(value->getBuffer(args...)));
|
|
} else {
|
|
// release(valueBuffer[0])
|
|
swift_release(
|
|
*reinterpret_cast<HeapObject **>(value->getBuffer(args...)));
|
|
}
|
|
}
|
|
|
|
enum class Dest {
|
|
Assign,
|
|
Init,
|
|
};
|
|
enum class Source {
|
|
Copy,
|
|
Take
|
|
};
|
|
|
|
template <class Container, class... A>
|
|
static void copyReference(Container *dest, Container *src, Dest d, Source s,
|
|
A... args) {
|
|
auto *destRefAddr =
|
|
reinterpret_cast<HeapObject **>(dest->getBuffer(args...));
|
|
|
|
// Load the source reference.
|
|
auto *srcRef = *reinterpret_cast<HeapObject **>(src->getBuffer(args...));
|
|
|
|
// Load the old destination reference so we can release it later if this is
|
|
// an assignment.
|
|
HeapObject *destRef = d == Dest::Assign ? *destRefAddr : nullptr;
|
|
|
|
// Do the assignment.
|
|
*destRefAddr = srcRef;
|
|
|
|
// If we copy the source retain the reference.
|
|
if (s == Source::Copy)
|
|
swift_retain(srcRef);
|
|
|
|
// If we have an assignment release the old reference.
|
|
if (d == Dest::Assign)
|
|
swift_release(destRef);
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *initializeWithCopy(Container *dest, Container *src,
|
|
A... args) {
|
|
src->copyTypeInto(dest, args...);
|
|
auto *type = src->getType();
|
|
auto *vwt = type->getValueWitnesses();
|
|
|
|
if (vwt->isValueInline()) {
|
|
auto *destValue =
|
|
reinterpret_cast<OpaqueValue *>(dest->getBuffer(args...));
|
|
auto *srcValue =
|
|
reinterpret_cast<OpaqueValue *>(src->getBuffer(args...));
|
|
|
|
type->vw_initializeWithCopy(destValue, srcValue);
|
|
} else {
|
|
// initWithCopy of the reference to the cow box.
|
|
copyReference(dest, src, Dest::Init, Source::Copy, args...);
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *initializeWithTake(Container *dest, Container *src,
|
|
A... args) {
|
|
src->copyTypeInto(dest, args...);
|
|
auto from = src->getBuffer(args...);
|
|
auto to = dest->getBuffer(args...);
|
|
memcpy(to, from, sizeof(ValueBuffer));
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *assignWithCopy(Container *dest, Container *src,
|
|
A... args) {
|
|
auto srcType = src->getType();
|
|
auto destType = dest->getType();
|
|
if (src == dest)
|
|
return dest;
|
|
if (srcType == destType) {
|
|
// Types match.
|
|
auto *vwt = srcType->getValueWitnesses();
|
|
|
|
if (vwt->isValueInline()) {
|
|
// Inline.
|
|
auto *destValue =
|
|
reinterpret_cast<OpaqueValue *>(dest->getBuffer(args...));
|
|
auto *srcValue =
|
|
reinterpret_cast<OpaqueValue *>(src->getBuffer(args...));
|
|
// assignWithCopy.
|
|
srcType->vw_assignWithCopy(destValue, srcValue);
|
|
} else {
|
|
// Outline (boxed value).
|
|
// assignWithCopy.
|
|
copyReference(dest, src, Dest::Assign, Source::Copy, args...);
|
|
}
|
|
} else {
|
|
// Different types.
|
|
auto *destVwt = destType->getValueWitnesses();
|
|
auto *srcVwt = srcType->getValueWitnesses();
|
|
if (destVwt->isValueInline()) {
|
|
// Inline destination value.
|
|
ValueBuffer tmpBuffer;
|
|
auto *opaqueTmpBuffer = reinterpret_cast<OpaqueValue *>(&tmpBuffer);
|
|
auto *destValue =
|
|
reinterpret_cast<OpaqueValue *>(dest->getBuffer(args...));
|
|
auto *srcValue =
|
|
reinterpret_cast<OpaqueValue *>(src->getBuffer(args...));
|
|
|
|
// Move dest value aside so we can destroy it later.
|
|
destType->vw_initializeWithTake(opaqueTmpBuffer, destValue);
|
|
|
|
src->copyTypeInto(dest, args...);
|
|
if (srcVwt->isValueInline()) {
|
|
// Inline src value.
|
|
|
|
srcType->vw_initializeWithCopy(destValue, srcValue);
|
|
} else {
|
|
// Outline src value.
|
|
|
|
// initWithCopy of reference to cow box.
|
|
copyReference(dest, src, Dest::Init, Source::Copy, args...);
|
|
}
|
|
|
|
// Finally, destroy the old dest value.
|
|
destType->vw_destroy(opaqueTmpBuffer);
|
|
} else {
|
|
// Outline destination value.
|
|
|
|
// Get the dest reference so we can release it later.
|
|
auto *destRef =
|
|
*reinterpret_cast<HeapObject **>(dest->getBuffer(args...));
|
|
|
|
src->copyTypeInto(dest, args...);
|
|
if (srcVwt->isValueInline()) {
|
|
|
|
// initWithCopy.
|
|
auto *destValue =
|
|
reinterpret_cast<OpaqueValue *>(dest->getBuffer(args...));
|
|
auto *srcValue =
|
|
reinterpret_cast<OpaqueValue *>(src->getBuffer(args...));
|
|
srcType->vw_initializeWithCopy(destValue, srcValue);
|
|
} else {
|
|
|
|
// initWithCopy of reference to cow box.
|
|
copyReference(dest, src, Dest::Init, Source::Copy, args...);
|
|
}
|
|
|
|
// Release dest reference.
|
|
swift_release(destRef);
|
|
}
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *assignWithTake(Container *dest, Container *src,
|
|
A... args) {
|
|
auto srcType = src->getType();
|
|
auto destType = dest->getType();
|
|
if (src == dest)
|
|
return dest;
|
|
|
|
if (srcType == destType) {
|
|
// Types match.
|
|
|
|
auto *vwt = srcType->getValueWitnesses();
|
|
if (vwt->isValueInline()) {
|
|
// Inline.
|
|
|
|
auto *destValue =
|
|
reinterpret_cast<OpaqueValue *>(dest->getBuffer(args...));
|
|
auto *srcValue =
|
|
reinterpret_cast<OpaqueValue *>(src->getBuffer(args...));
|
|
// assignWithTake.
|
|
srcType->vw_assignWithTake(destValue, srcValue);
|
|
} else {
|
|
// Outline (boxed value).
|
|
|
|
// assignWithTake of reference to cow box.
|
|
copyReference(dest, src, Dest::Assign, Source::Take, args...);
|
|
}
|
|
} else {
|
|
// Different types.
|
|
|
|
auto *destVwt = destType->getValueWitnesses();
|
|
auto *srcVwt = srcType->getValueWitnesses();
|
|
if (destVwt->isValueInline()) {
|
|
// Inline destination value.
|
|
|
|
ValueBuffer tmpBuffer;
|
|
auto *opaqueTmpBuffer = reinterpret_cast<OpaqueValue *>(&tmpBuffer);
|
|
auto *destValue =
|
|
reinterpret_cast<OpaqueValue *>(dest->getBuffer(args...));
|
|
auto *srcValue =
|
|
reinterpret_cast<OpaqueValue *>(src->getBuffer(args...));
|
|
|
|
// Move dest value aside.
|
|
destType->vw_initializeWithTake(opaqueTmpBuffer, destValue);
|
|
|
|
src->copyTypeInto(dest, args...);
|
|
if (srcVwt->isValueInline()) {
|
|
// Inline src value.
|
|
|
|
srcType->vw_initializeWithTake(destValue, srcValue);
|
|
} else {
|
|
// Outline src value.
|
|
|
|
// initWithTake of reference to cow box.
|
|
copyReference(dest, src, Dest::Init, Source::Take, args...);
|
|
}
|
|
|
|
// Destroy old dest value.
|
|
destType->vw_destroy(opaqueTmpBuffer);
|
|
} else {
|
|
// Outline destination value.
|
|
|
|
// Get the old dest reference.
|
|
auto *destRef =
|
|
*reinterpret_cast<HeapObject **>(dest->getBuffer(args...));
|
|
|
|
src->copyTypeInto(dest, args...);
|
|
if (srcVwt->isValueInline()) {
|
|
// initWithCopy.
|
|
|
|
auto *destValue =
|
|
reinterpret_cast<OpaqueValue *>(dest->getBuffer(args...));
|
|
auto *srcValue =
|
|
reinterpret_cast<OpaqueValue *>(src->getBuffer(args...));
|
|
// initWithTake.
|
|
srcType->vw_initializeWithTake(destValue, srcValue);
|
|
} else {
|
|
|
|
// initWithTake of reference to cow box.
|
|
copyReference(dest, src, Dest::Init, Source::Take, args...);
|
|
}
|
|
|
|
// Release old dest reference.
|
|
swift_release(destRef);
|
|
}
|
|
}
|
|
return dest;
|
|
}
|
|
};
|
|
|
|
/// 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 <unsigned NumWitnessTables>
|
|
struct SWIFT_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 <unsigned NumWitnessTables>
|
|
struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBox
|
|
: OpaqueExistentialBoxBase {
|
|
struct Container : FixedOpaqueExistentialContainer<NumWitnessTables> {
|
|
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 = true;
|
|
static constexpr unsigned numExtraInhabitants =
|
|
swift_getHeapObjectExtraInhabitantCount();
|
|
|
|
static void storeExtraInhabitantTag(Container *dest, unsigned tag) {
|
|
swift_storeHeapObjectExtraInhabitant(
|
|
const_cast<HeapObject **>(
|
|
reinterpret_cast<const HeapObject **>(&dest->Header.Type)),
|
|
tag - 1);
|
|
}
|
|
|
|
static unsigned getExtraInhabitantTag(const Container *src) {
|
|
return swift_getHeapObjectExtraInhabitantIndex(const_cast<HeapObject **>(
|
|
reinterpret_cast<const HeapObject *const *>(&src->Header.Type))) + 1;
|
|
}
|
|
};
|
|
|
|
/// A non-fixed box implementation class for an opaque existential
|
|
/// type with a dynamic number of witness tables.
|
|
struct SWIFT_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<const ExistentialTypeMetadata*>(self);
|
|
return castSelf->Flags.getNumWitnessTables();
|
|
}
|
|
|
|
static size_t getAlignment(unsigned numWitnessTables) {
|
|
return std::max(alignof(void*), alignof(ValueBuffer));
|
|
}
|
|
static size_t getSize(unsigned numWitnessTables) {
|
|
constexpr size_t base = sizeof(OpaqueExistentialContainer);
|
|
static_assert(base > 0, "stride needs base size > 0");
|
|
return base + 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 =
|
|
swift_getHeapObjectExtraInhabitantCount();
|
|
|
|
static void storeExtraInhabitantTag(Container *dest, unsigned tag) {
|
|
swift_storeHeapObjectExtraInhabitant(
|
|
(HeapObject**)(uintptr_t)&dest->Header.Type, tag - 1);
|
|
}
|
|
|
|
static unsigned getExtraInhabitantTag(const Container *src) {
|
|
return swift_getHeapObjectExtraInhabitantIndex(
|
|
(HeapObject* const *)(uintptr_t)&src->Header.Type) + 1;
|
|
}
|
|
};
|
|
|
|
/// A common base class for fixed and non-fixed class-existential box
|
|
/// implementations.
|
|
struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBoxBase
|
|
: ExistentialBoxBase<ClassExistentialBoxBase> {
|
|
static constexpr unsigned numExtraInhabitants =
|
|
swift_getHeapObjectExtraInhabitantCount();
|
|
|
|
template <class Container, class... A>
|
|
static void destroy(Container *value, A... args) {
|
|
swift_unknownObjectRelease(*value->getValueSlot());
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *initializeWithCopy(Container *dest, Container *src,
|
|
A... args) {
|
|
src->copyTypeInto(dest, args...);
|
|
auto newValue = *src->getValueSlot();
|
|
*dest->getValueSlot() = newValue;
|
|
swift_unknownObjectRetain(newValue);
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *initializeWithTake(Container *dest, Container *src,
|
|
A... args) {
|
|
src->copyTypeInto(dest, args...);
|
|
*dest->getValueSlot() = *src->getValueSlot();
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
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_unknownObjectRetain(newValue);
|
|
swift_unknownObjectRelease(oldValue);
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
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_unknownObjectRelease(oldValue);
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static void storeExtraInhabitantTag(Container *dest, unsigned tag, A... args) {
|
|
swift_storeHeapObjectExtraInhabitant((HeapObject**) dest->getValueSlot(),
|
|
tag - 1);
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static int getExtraInhabitantTag(const Container *src, A... args) {
|
|
return swift_getHeapObjectExtraInhabitantIndex(
|
|
(HeapObject* const *) src->getValueSlot()) + 1;
|
|
}
|
|
};
|
|
|
|
/// A box implementation class for an existential container with
|
|
/// a class constraint and a fixed number of protocol witness tables.
|
|
template <unsigned NumWitnessTables>
|
|
struct SWIFT_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 a class existential
|
|
/// type with a dynamic number of witness tables.
|
|
struct SWIFT_LIBRARY_VISIBILITY NonFixedClassExistentialBox
|
|
: ClassExistentialBoxBase {
|
|
struct Container {
|
|
ClassExistentialContainer Header;
|
|
|
|
static unsigned getNumWitnessTables(const Metadata *self) {
|
|
auto castSelf = static_cast<const ExistentialTypeMetadata*>(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) {
|
|
constexpr size_t base = sizeof(ClassExistentialContainer);
|
|
static_assert(base > 0, "stride needs base size > 0");
|
|
return base + 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 SWIFT_LIBRARY_VISIBILITY ExistentialMetatypeBoxBase
|
|
: ExistentialBoxBase<ExistentialMetatypeBoxBase> {
|
|
static constexpr unsigned numExtraInhabitants =
|
|
swift_getHeapObjectExtraInhabitantCount();
|
|
|
|
template <class Container, class... A>
|
|
static void destroy(Container *value, A... args) {
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *initializeWithCopy(Container *dest, Container *src,
|
|
A... args) {
|
|
src->copyTypeInto(dest, args...);
|
|
*dest->getValueSlot() = *src->getValueSlot();
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *initializeWithTake(Container *dest, Container *src,
|
|
A... args) {
|
|
src->copyTypeInto(dest, args...);
|
|
*dest->getValueSlot() = *src->getValueSlot();
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *assignWithCopy(Container *dest, Container *src,
|
|
A... args) {
|
|
src->copyTypeInto(dest, args...);
|
|
*dest->getValueSlot() = *src->getValueSlot();
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static Container *assignWithTake(Container *dest, Container *src,
|
|
A... args) {
|
|
src->copyTypeInto(dest, args...);
|
|
*dest->getValueSlot() = *src->getValueSlot();
|
|
return dest;
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static void storeExtraInhabitantTag(Container *dest, unsigned tag, A... args) {
|
|
Metadata **MD = const_cast<Metadata **>(dest->getValueSlot());
|
|
swift_storeHeapObjectExtraInhabitant(reinterpret_cast<HeapObject **>(MD),
|
|
tag - 1);
|
|
}
|
|
|
|
template <class Container, class... A>
|
|
static int getExtraInhabitantTag(const Container *src, A... args) {
|
|
Metadata **MD = const_cast<Metadata **>(src->getValueSlot());
|
|
return swift_getHeapObjectExtraInhabitantIndex(
|
|
reinterpret_cast<HeapObject *const *>(MD)) + 1;
|
|
}
|
|
};
|
|
|
|
/// A box implementation class for an existential metatype container
|
|
/// with a fixed number of protocol witness tables.
|
|
template <unsigned NumWitnessTables>
|
|
struct SWIFT_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 SWIFT_LIBRARY_VISIBILITY NonFixedExistentialMetatypeBox
|
|
: ExistentialMetatypeBoxBase {
|
|
struct Container {
|
|
ExistentialMetatypeContainer Header;
|
|
|
|
static unsigned getNumWitnessTables(const Metadata *self) {
|
|
auto castSelf = static_cast<const ExistentialMetatypeMetadata*>(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) {
|
|
constexpr size_t base = sizeof(ExistentialMetatypeContainer);
|
|
static_assert(base > 0, "stride needs base size > 0");
|
|
return base + 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 */
|