Skip to content

Commit 2041887

Browse files
committed
[Runtime] Handle different types for src and dest in existentialAssignWithCopy
rdar://117083470 An existential can contain a different type than the one that is being assigned, so we have to check the types and handle the values accordingly.
1 parent bc71e34 commit 2041887

File tree

2 files changed

+68
-3
lines changed

2 files changed

+68
-3
lines changed

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,14 +1435,32 @@ static void existentialAssignWithCopy(const Metadata *metadata,
14351435
uint8_t *dest,
14361436
uint8_t *src) {
14371437
uintptr_t _addrOffset = addrOffset;
1438-
auto *type = getExistentialTypeMetadata((OpaqueValue*)(src + _addrOffset));
1438+
auto *srcType = getExistentialTypeMetadata((OpaqueValue*)(src + _addrOffset));
1439+
auto *destType = getExistentialTypeMetadata((OpaqueValue*)(dest + _addrOffset));
14391440
auto *destObject = (OpaqueValue *)(dest + _addrOffset);
14401441
auto *srcObject = (OpaqueValue *)(src + _addrOffset);
14411442
addrOffset = _addrOffset + (sizeof(uintptr_t) * NumWords_ValueBuffer);
1442-
if (type->getValueWitnesses()->isValueInline()) {
1443-
type->vw_assignWithCopy(destObject, srcObject);
1443+
1444+
if (srcType == destType) {
1445+
if (srcType->getValueWitnesses()->isValueInline()) {
1446+
srcType->vw_assignWithCopy(destObject, srcObject);
1447+
} else {
1448+
swift_release(*(HeapObject**)destObject);
1449+
memcpy(destObject, srcObject, sizeof(uintptr_t));
1450+
swift_retain(*(HeapObject**)srcObject);
1451+
}
1452+
return;
1453+
}
1454+
1455+
if (destType->getValueWitnesses()->isValueInline()) {
1456+
destType->vw_destroy(destObject);
14441457
} else {
14451458
swift_release(*(HeapObject**)destObject);
1459+
}
1460+
1461+
if (srcType->getValueWitnesses()->isValueInline()) {
1462+
srcType->vw_initializeWithCopy(destObject, srcObject);
1463+
} else {
14461464
memcpy(destObject, srcObject, sizeof(uintptr_t));
14471465
swift_retain(*(HeapObject**)srcObject);
14481466
}

test/Interpreter/layout_string_witnesses_static.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,12 @@ struct StructWithSomeProtocolInline: SomeProtocol {
308308
let x: SimpleClass
309309
}
310310

311+
struct StructWithSomeProtocolInlineShifted: SomeProtocol {
312+
let y: Int = 0
313+
let y2: Int = 0
314+
let x: SimpleClass
315+
}
316+
311317
func testExistentialStructInline() {
312318
let ptr = UnsafeMutablePointer<ExistentialWrapper>.allocate(capacity: 1)
313319

@@ -396,6 +402,47 @@ func testExistentialStructBox() {
396402

397403
testExistentialStructBox()
398404

405+
func testExistentialStructTypeChange() {
406+
let ptr = UnsafeMutablePointer<ExistentialWrapper>.allocate(capacity: 1)
407+
408+
do {
409+
let x = StructWithSomeProtocolInline(x: SimpleClass(x: 23))
410+
testInit(ptr, to: createExistentialWrapper(x))
411+
}
412+
413+
do {
414+
let y = StructWithSomeProtocolInlineShifted(x: SimpleClass(x: 32))
415+
416+
// CHECK: Before deinit
417+
print("Before deinit")
418+
419+
// CHECK-NEXT: SimpleClass deinitialized!
420+
var wrapper = createExistentialWrapper(y)
421+
testAssignCopy(ptr, from: &wrapper)
422+
}
423+
424+
do {
425+
let z = StructWithSomeProtocolBox(x: SimpleClass(x: 32))
426+
427+
// CHECK-NEXT: Before deinit
428+
print("Before deinit")
429+
430+
// CHECK-NEXT: SimpleClass deinitialized!
431+
var wrapper = createExistentialWrapper(z)
432+
testAssignCopy(ptr, from: &wrapper)
433+
}
434+
435+
// CHECK-NEXT: Before deinit
436+
print("Before deinit")
437+
438+
// CHECK-NEXT: SimpleClass deinitialized!
439+
testDestroy(ptr)
440+
441+
ptr.deallocate()
442+
}
443+
444+
testExistentialStructTypeChange()
445+
399446
func testAnyWrapper() {
400447
let ptr = UnsafeMutablePointer<AnyWrapper>.allocate(capacity: 1)
401448

0 commit comments

Comments
 (0)