Skip to content

Commit 662f8d4

Browse files
authored
Merge pull request #85346 from mikeash/fix-extended-existential-copying
[Runtime] Fix copying in extended existential value witnesses.
2 parents e2123e1 + 7bb9579 commit 662f8d4

File tree

2 files changed

+133
-54
lines changed

2 files changed

+133
-54
lines changed

stdlib/public/runtime/ExistentialMetadataImpl.h

Lines changed: 45 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,20 @@ namespace swift {
2525
namespace metadataimpl {
2626

2727
/// A common base class for opaque-existential and class-existential boxes.
28-
template <typename Impl> struct SWIFT_LIBRARY_VISIBILITY ExistentialBoxBase {};
28+
template <typename Impl>
29+
struct SWIFT_LIBRARY_VISIBILITY ExistentialBoxBase {
30+
template <class Container, class... A>
31+
static void copyBytes(Container *dest, Container *src, A... args) {
32+
memcpy(dest, src, src->getContainerStride(args...));
33+
}
34+
35+
template <class Container, class... A>
36+
static void copyTypeBytes(Container *dest, Container *src, A...args) {
37+
auto valueBytes = src->getValueSize();
38+
auto toCopy = src->getContainerStride(args...) - valueBytes;
39+
memcpy((char *)dest + valueBytes, (char *)src + valueBytes, toCopy);
40+
}
41+
};
2942

3043
/// A common base class for fixed and non-fixed opaque-existential box
3144
/// implementations.
@@ -83,7 +96,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
8396
template <class Container, class... A>
8497
static Container *initializeWithCopy(Container *dest, Container *src,
8598
A... args) {
86-
src->copyTypeInto(dest, args...);
99+
copyTypeBytes(dest, src, args...);
87100
auto *type = src->getType();
88101
auto *vwt = type->getValueWitnesses();
89102

@@ -104,10 +117,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
104117
template <class Container, class... A>
105118
static Container *initializeWithTake(Container *dest, Container *src,
106119
A... args) {
107-
src->copyTypeInto(dest, args...);
108-
auto from = src->getBuffer(args...);
109-
auto to = dest->getBuffer(args...);
110-
memcpy(to, from, sizeof(ValueBuffer));
120+
copyBytes(dest, src, args...);
111121
return dest;
112122
}
113123

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

154-
src->copyTypeInto(dest, args...);
164+
copyTypeBytes(dest, src, args...);
155165
if (srcVwt->isValueInline()) {
156166
// Inline src value.
157167

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

175-
src->copyTypeInto(dest, args...);
185+
copyTypeBytes(dest, src, args...);
176186
if (srcVwt->isValueInline()) {
177187

178188
// initWithCopy.
@@ -239,7 +249,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
239249
// Move dest value aside.
240250
destType->vw_initializeWithTake(opaqueTmpBuffer, destValue);
241251

242-
src->copyTypeInto(dest, args...);
252+
copyTypeBytes(dest, src, args...);
243253
if (srcVwt->isValueInline()) {
244254
// Inline src value.
245255

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

263-
src->copyTypeInto(dest, args...);
273+
copyTypeBytes(dest, src, args...);
264274
if (srcVwt->isValueInline()) {
265275
// initWithCopy.
266276

@@ -291,12 +301,20 @@ template <unsigned NumWitnessTables>
291301
struct SWIFT_LIBRARY_VISIBILITY FixedOpaqueExistentialContainer {
292302
OpaqueExistentialContainer Header;
293303
const void *WitnessTables[NumWitnessTables];
304+
305+
static size_t getValueSize() {
306+
return sizeof(Header.Buffer);
307+
}
294308
};
295309
// We need to be able to instantiate for NumWitnessTables==0, which
296310
// requires an explicit specialization.
297311
template <>
298312
struct FixedOpaqueExistentialContainer<0> {
299313
OpaqueExistentialContainer Header;
314+
315+
static size_t getValueSize() {
316+
return sizeof(Header.Buffer);
317+
}
300318
};
301319

302320
/// A box implementation class for an opaque existential type with
@@ -311,10 +329,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBox
311329
ValueBuffer *getBuffer() {
312330
return &this->Header.Buffer;
313331
}
314-
void copyTypeInto(Container *dest) const {
315-
this->Header.copyTypeInto(&dest->Header, NumWitnessTables);
316-
}
317-
332+
318333
static size_t getContainerStride() {
319334
return sizeof(Container);
320335
}
@@ -355,9 +370,6 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedOpaqueExistentialBox
355370
ValueBuffer *getBuffer(const Metadata *self) {
356371
return &Header.Buffer;
357372
}
358-
void copyTypeInto(Container *dest, const Metadata *self) {
359-
Header.copyTypeInto(&dest->Header, getNumWitnessTables(self));
360-
}
361373

362374
static unsigned getNumWitnessTables(const Metadata *self) {
363375
auto castSelf = static_cast<const ExistentialTypeMetadata*>(self);
@@ -377,7 +389,11 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedOpaqueExistentialBox
377389
}
378390

379391
static size_t getContainerStride(const Metadata *self) {
380-
return getStride(getNumWitnessTables(self));
392+
return self->vw_stride();
393+
}
394+
395+
static size_t getValueSize() {
396+
return sizeof(Header.Buffer);
381397
}
382398
};
383399

@@ -411,28 +427,25 @@ struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBoxBase
411427
template <class Container, class... A>
412428
static Container *initializeWithCopy(Container *dest, Container *src,
413429
A... args) {
414-
src->copyTypeInto(dest, args...);
415430
auto newValue = *src->getValueSlot();
416-
*dest->getValueSlot() = newValue;
431+
copyBytes(dest, src, args...);
417432
swift_unknownObjectRetain(newValue);
418433
return dest;
419434
}
420435

421436
template <class Container, class... A>
422437
static Container *initializeWithTake(Container *dest, Container *src,
423438
A... args) {
424-
src->copyTypeInto(dest, args...);
425-
*dest->getValueSlot() = *src->getValueSlot();
439+
copyBytes(dest, src, args...);
426440
return dest;
427441
}
428442

429443
template <class Container, class... A>
430444
static Container *assignWithCopy(Container *dest, Container *src,
431445
A... args) {
432-
src->copyTypeInto(dest, args...);
433446
auto newValue = *src->getValueSlot();
434447
auto oldValue = *dest->getValueSlot();
435-
*dest->getValueSlot() = newValue;
448+
copyBytes(dest, src, args...);
436449
swift_unknownObjectRetain(newValue);
437450
swift_unknownObjectRelease(oldValue);
438451
return dest;
@@ -441,10 +454,8 @@ struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBoxBase
441454
template <class Container, class... A>
442455
static Container *assignWithTake(Container *dest, Container *src,
443456
A... args) {
444-
src->copyTypeInto(dest, args...);
445-
auto newValue = *src->getValueSlot();
446457
auto oldValue = *dest->getValueSlot();
447-
*dest->getValueSlot() = newValue;
458+
copyBytes(dest, src, args...);
448459
swift_unknownObjectRelease(oldValue);
449460
return dest;
450461
}
@@ -470,10 +481,6 @@ struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBox : ClassExistentialBoxBase {
470481
ClassExistentialContainer Header;
471482
const void *TypeInfo[NumWitnessTables];
472483

473-
void copyTypeInto(Container *dest) const {
474-
for (unsigned i = 0; i != NumWitnessTables; ++i)
475-
dest->TypeInfo[i] = TypeInfo[i];
476-
}
477484
void **getValueSlot() { return &Header.Value; }
478485
void * const *getValueSlot() const { return &Header.Value; }
479486

@@ -501,10 +508,6 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedClassExistentialBox
501508
return castSelf->Flags.getNumWitnessTables();
502509
}
503510

504-
void copyTypeInto(Container *dest, const Metadata *self) {
505-
Header.copyTypeInto(&dest->Header, getNumWitnessTables(self));
506-
}
507-
508511
void **getValueSlot() { return &Header.Value; }
509512
void * const *getValueSlot() const { return &Header.Value; }
510513

@@ -520,7 +523,7 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedClassExistentialBox
520523
return getSize(numWitnessTables);
521524
}
522525
static size_t getContainerStride(const Metadata *self) {
523-
return getStride(getNumWitnessTables(self));
526+
return self->vw_stride();
524527
}
525528
};
526529
using type = Container;
@@ -540,32 +543,28 @@ struct SWIFT_LIBRARY_VISIBILITY ExistentialMetatypeBoxBase
540543
template <class Container, class... A>
541544
static Container *initializeWithCopy(Container *dest, Container *src,
542545
A... args) {
543-
src->copyTypeInto(dest, args...);
544-
*dest->getValueSlot() = *src->getValueSlot();
545-
return dest;
546+
copyBytes(dest, src, args...);
547+
return dest;
546548
}
547549

548550
template <class Container, class... A>
549551
static Container *initializeWithTake(Container *dest, Container *src,
550552
A... args) {
551-
src->copyTypeInto(dest, args...);
552-
*dest->getValueSlot() = *src->getValueSlot();
553+
copyBytes(dest, src, args...);
553554
return dest;
554555
}
555556

556557
template <class Container, class... A>
557558
static Container *assignWithCopy(Container *dest, Container *src,
558559
A... args) {
559-
src->copyTypeInto(dest, args...);
560-
*dest->getValueSlot() = *src->getValueSlot();
560+
copyBytes(dest, src, args...);
561561
return dest;
562562
}
563563

564564
template <class Container, class... A>
565565
static Container *assignWithTake(Container *dest, Container *src,
566566
A... args) {
567-
src->copyTypeInto(dest, args...);
568-
*dest->getValueSlot() = *src->getValueSlot();
567+
copyBytes(dest, src, args...);
569568
return dest;
570569
}
571570

@@ -593,10 +592,6 @@ struct SWIFT_LIBRARY_VISIBILITY ExistentialMetatypeBox
593592
ExistentialMetatypeContainer Header;
594593
const void *TypeInfo[NumWitnessTables];
595594

596-
void copyTypeInto(Container *dest) const {
597-
for (unsigned i = 0; i != NumWitnessTables; ++i)
598-
dest->TypeInfo[i] = TypeInfo[i];
599-
}
600595
const Metadata **getValueSlot() { return &Header.Value; }
601596
const Metadata * const *getValueSlot() const { return &Header.Value; }
602597

@@ -624,10 +619,6 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedExistentialMetatypeBox
624619
return castSelf->Flags.getNumWitnessTables();
625620
}
626621

627-
void copyTypeInto(Container *dest, const Metadata *self) {
628-
Header.copyTypeInto(&dest->Header, getNumWitnessTables(self));
629-
}
630-
631622
const Metadata **getValueSlot() { return &Header.Value; }
632623
const Metadata * const *getValueSlot() const { return &Header.Value; }
633624

@@ -643,7 +634,7 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedExistentialMetatypeBox
643634
return getSize(numWitnessTables);
644635
}
645636
static size_t getContainerStride(const Metadata *self) {
646-
return getStride(getNumWitnessTables(self));
637+
return self->vw_stride();
647638
}
648639
};
649640
using type = Container;
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: %target-run-simple-swift | %FileCheck %s
2+
3+
// UNSUPPORTED: use_os_stdlib
4+
// UNSUPPORTED: back_deployment_runtime
5+
// REQUIRES: OS=macosx
6+
// REQUIRES: executable_test
7+
8+
protocol P1<P1T> {
9+
associatedtype P1T
10+
11+
func printValue()
12+
}
13+
14+
protocol P2<P2T> {
15+
associatedtype P2T
16+
}
17+
18+
protocol P3<P3T> {
19+
associatedtype P3T
20+
}
21+
22+
struct Small: P1, P2, P3 {
23+
typealias P1T = Int
24+
typealias P2T = Int
25+
typealias P3T = Int
26+
27+
var str = "I am Small"
28+
29+
func printValue() { print(str) }
30+
}
31+
32+
struct Big: P1, P2, P3 {
33+
typealias P1T = Int
34+
typealias P2T = Int
35+
typealias P3T = Int
36+
37+
var str = "I am Big"
38+
var str2 = ""
39+
var str3 = ""
40+
41+
func printValue() { print(str) }
42+
}
43+
44+
class Class: P1, P2, P3 {
45+
typealias P1T = Int
46+
typealias P2T = Int
47+
typealias P3T = Int
48+
49+
var str = "I am Class"
50+
51+
func printValue() { print(str) }
52+
}
53+
54+
func test<T>(_ value: T) {
55+
var array: [T] = []
56+
array.append(value)
57+
for v in array {
58+
(v as? P1)?.printValue()
59+
}
60+
}
61+
62+
// CHECK: I am Small
63+
test(Small() as any P1<Int>)
64+
// CHECK: I am Small
65+
test(Small() as any P1<Int> & P2<Int>)
66+
// CHECK: I am Small
67+
test(Small() as any P1<Int> & P2<Int> & P3<Int>)
68+
69+
// CHECK: I am Big
70+
test(Big() as any P1<Int>)
71+
// CHECK: I am Big
72+
test(Big() as any P1<Int> & P2<Int>)
73+
// CHECK: I am Big
74+
test(Big() as any P1<Int> & P2<Int> & P3<Int>)
75+
76+
// CHECK: I am Class
77+
test(Class() as any P1<Int>)
78+
// CHECK: I am Class
79+
test(Class() as any P1<Int> & P2<Int>)
80+
// CHECK: I am Class
81+
test(Class() as any P1<Int> & P2<Int> & P3<Int>)
82+
83+
// CHECK: I am Class
84+
test(Class() as any AnyObject & P1<Int>)
85+
// CHECK: I am Class
86+
test(Class() as any AnyObject & P1<Int> & P2<Int>)
87+
// CHECK: I am Class
88+
test(Class() as any AnyObject & P1<Int> & P2<Int> & P3<Int>)

0 commit comments

Comments
 (0)