Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 45 additions & 54 deletions stdlib/public/runtime/ExistentialMetadataImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,20 @@ namespace swift {
namespace metadataimpl {

/// A common base class for opaque-existential and class-existential boxes.
template <typename Impl> struct SWIFT_LIBRARY_VISIBILITY ExistentialBoxBase {};
template <typename Impl>
struct SWIFT_LIBRARY_VISIBILITY ExistentialBoxBase {
template <class Container, class... A>
static void copyBytes(Container *dest, Container *src, A... args) {
memcpy(dest, src, src->getContainerStride(args...));
}

template <class Container, class... A>
static void copyTypeBytes(Container *dest, Container *src, A...args) {
auto valueBytes = src->getValueSize();
auto toCopy = src->getContainerStride(args...) - valueBytes;
memcpy((char *)dest + valueBytes, (char *)src + valueBytes, toCopy);
}
};

/// A common base class for fixed and non-fixed opaque-existential box
/// implementations.
Expand Down Expand Up @@ -83,7 +96,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
template <class Container, class... A>
static Container *initializeWithCopy(Container *dest, Container *src,
A... args) {
src->copyTypeInto(dest, args...);
copyTypeBytes(dest, src, args...);
auto *type = src->getType();
auto *vwt = type->getValueWitnesses();

Expand All @@ -104,10 +117,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
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));
copyBytes(dest, src, args...);
return dest;
}

Expand Down Expand Up @@ -151,7 +161,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
// Move dest value aside so we can destroy it later.
destType->vw_initializeWithTake(opaqueTmpBuffer, destValue);

src->copyTypeInto(dest, args...);
copyTypeBytes(dest, src, args...);
if (srcVwt->isValueInline()) {
// Inline src value.

Expand All @@ -172,7 +182,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
auto *destRef =
*reinterpret_cast<HeapObject **>(dest->getBuffer(args...));

src->copyTypeInto(dest, args...);
copyTypeBytes(dest, src, args...);
if (srcVwt->isValueInline()) {

// initWithCopy.
Expand Down Expand Up @@ -239,7 +249,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
// Move dest value aside.
destType->vw_initializeWithTake(opaqueTmpBuffer, destValue);

src->copyTypeInto(dest, args...);
copyTypeBytes(dest, src, args...);
if (srcVwt->isValueInline()) {
// Inline src value.

Expand All @@ -260,7 +270,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
auto *destRef =
*reinterpret_cast<HeapObject **>(dest->getBuffer(args...));

src->copyTypeInto(dest, args...);
copyTypeBytes(dest, src, args...);
if (srcVwt->isValueInline()) {
// initWithCopy.

Expand Down Expand Up @@ -291,12 +301,20 @@ template <unsigned NumWitnessTables>
struct SWIFT_LIBRARY_VISIBILITY FixedOpaqueExistentialContainer {
OpaqueExistentialContainer Header;
const void *WitnessTables[NumWitnessTables];

static size_t getValueSize() {
return sizeof(Header.Buffer);
}
};
// We need to be able to instantiate for NumWitnessTables==0, which
// requires an explicit specialization.
template <>
struct FixedOpaqueExistentialContainer<0> {
OpaqueExistentialContainer Header;

static size_t getValueSize() {
return sizeof(Header.Buffer);
}
};

/// A box implementation class for an opaque existential type with
Expand All @@ -311,10 +329,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBox
ValueBuffer *getBuffer() {
return &this->Header.Buffer;
}
void copyTypeInto(Container *dest) const {
this->Header.copyTypeInto(&dest->Header, NumWitnessTables);
}


static size_t getContainerStride() {
return sizeof(Container);
}
Expand Down Expand Up @@ -355,9 +370,6 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedOpaqueExistentialBox
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);
Expand All @@ -377,7 +389,11 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedOpaqueExistentialBox
}

static size_t getContainerStride(const Metadata *self) {
return getStride(getNumWitnessTables(self));
return self->vw_stride();
}

static size_t getValueSize() {
return sizeof(Header.Buffer);
}
};

Expand Down Expand Up @@ -411,28 +427,25 @@ struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBoxBase
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;
copyBytes(dest, src, args...);
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();
copyBytes(dest, src, args...);
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;
copyBytes(dest, src, args...);
swift_unknownObjectRetain(newValue);
swift_unknownObjectRelease(oldValue);
return dest;
Expand All @@ -441,10 +454,8 @@ struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBoxBase
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;
copyBytes(dest, src, args...);
swift_unknownObjectRelease(oldValue);
return dest;
}
Expand All @@ -470,10 +481,6 @@ struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBox : ClassExistentialBoxBase {
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; }

Expand Down Expand Up @@ -501,10 +508,6 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedClassExistentialBox
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; }

Expand All @@ -520,7 +523,7 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedClassExistentialBox
return getSize(numWitnessTables);
}
static size_t getContainerStride(const Metadata *self) {
return getStride(getNumWitnessTables(self));
return self->vw_stride();
}
};
using type = Container;
Expand All @@ -540,32 +543,28 @@ struct SWIFT_LIBRARY_VISIBILITY ExistentialMetatypeBoxBase
template <class Container, class... A>
static Container *initializeWithCopy(Container *dest, Container *src,
A... args) {
src->copyTypeInto(dest, args...);
*dest->getValueSlot() = *src->getValueSlot();
return dest;
copyBytes(dest, src, args...);
return dest;
}

template <class Container, class... A>
static Container *initializeWithTake(Container *dest, Container *src,
A... args) {
src->copyTypeInto(dest, args...);
*dest->getValueSlot() = *src->getValueSlot();
copyBytes(dest, src, args...);
return dest;
}

template <class Container, class... A>
static Container *assignWithCopy(Container *dest, Container *src,
A... args) {
src->copyTypeInto(dest, args...);
*dest->getValueSlot() = *src->getValueSlot();
copyBytes(dest, src, args...);
return dest;
}

template <class Container, class... A>
static Container *assignWithTake(Container *dest, Container *src,
A... args) {
src->copyTypeInto(dest, args...);
*dest->getValueSlot() = *src->getValueSlot();
copyBytes(dest, src, args...);
return dest;
}

Expand Down Expand Up @@ -593,10 +592,6 @@ struct SWIFT_LIBRARY_VISIBILITY ExistentialMetatypeBox
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; }

Expand Down Expand Up @@ -624,10 +619,6 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedExistentialMetatypeBox
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; }

Expand All @@ -643,7 +634,7 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedExistentialMetatypeBox
return getSize(numWitnessTables);
}
static size_t getContainerStride(const Metadata *self) {
return getStride(getNumWitnessTables(self));
return self->vw_stride();
}
};
using type = Container;
Expand Down
88 changes: 88 additions & 0 deletions test/Interpreter/extended_existential_copying.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// RUN: %target-run-simple-swift | %FileCheck %s

// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: back_deployment_runtime
// REQUIRES: OS=macosx
// REQUIRES: executable_test

protocol P1<P1T> {
associatedtype P1T

func printValue()
}

protocol P2<P2T> {
associatedtype P2T
}

protocol P3<P3T> {
associatedtype P3T
}

struct Small: P1, P2, P3 {
typealias P1T = Int
typealias P2T = Int
typealias P3T = Int

var str = "I am Small"

func printValue() { print(str) }
}

struct Big: P1, P2, P3 {
typealias P1T = Int
typealias P2T = Int
typealias P3T = Int

var str = "I am Big"
var str2 = ""
var str3 = ""

func printValue() { print(str) }
}

class Class: P1, P2, P3 {
typealias P1T = Int
typealias P2T = Int
typealias P3T = Int

var str = "I am Class"

func printValue() { print(str) }
}

func test<T>(_ value: T) {
var array: [T] = []
array.append(value)
for v in array {
(v as? P1)?.printValue()
}
}

// CHECK: I am Small
test(Small() as any P1<Int>)
// CHECK: I am Small
test(Small() as any P1<Int> & P2<Int>)
// CHECK: I am Small
test(Small() as any P1<Int> & P2<Int> & P3<Int>)

// CHECK: I am Big
test(Big() as any P1<Int>)
// CHECK: I am Big
test(Big() as any P1<Int> & P2<Int>)
// CHECK: I am Big
test(Big() as any P1<Int> & P2<Int> & P3<Int>)

// CHECK: I am Class
test(Class() as any P1<Int>)
// CHECK: I am Class
test(Class() as any P1<Int> & P2<Int>)
// CHECK: I am Class
test(Class() as any P1<Int> & P2<Int> & P3<Int>)

// CHECK: I am Class
test(Class() as any AnyObject & P1<Int>)
// CHECK: I am Class
test(Class() as any AnyObject & P1<Int> & P2<Int>)
// CHECK: I am Class
test(Class() as any AnyObject & P1<Int> & P2<Int> & P3<Int>)