Skip to content

Commit 6ebe86c

Browse files
authored
[Runtime] Add layout string handling in swift_arrayAssignWithCopyFrontToBack (swiftlang#69979)
By using a specialize function, we only call through the witness table and fetch the layout string once for the whoe buffer, instead of once per element.
1 parent 12729da commit 6ebe86c

File tree

5 files changed

+141
-21
lines changed

5 files changed

+141
-21
lines changed

stdlib/public/runtime/Array.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ static void array_copy_operation(OpaqueValue *dest, OpaqueValue *src,
111111

112112
// Call the witness to do the copy.
113113
if (copyKind == ArrayCopy::NoAlias || copyKind == ArrayCopy::FrontToBack) {
114+
if (self->hasLayoutString() && destOp == ArrayDest::Init &&
115+
srcOp == ArraySource::Copy) {
116+
return swift_generic_arrayInitWithCopy(dest, src, count, stride, self);
117+
}
118+
119+
if (self->hasLayoutString() && destOp == ArrayDest::Assign &&
120+
srcOp == ArraySource::Copy) {
121+
return swift_generic_arrayAssignWithCopy(dest, src, count, stride, self);
122+
}
123+
114124
auto copy = get_witness_function<destOp, srcOp>(wtable);
115125
for (size_t i = 0; i < count; ++i) {
116126
auto offset = i * stride;
@@ -125,10 +135,6 @@ static void array_copy_operation(OpaqueValue *dest, OpaqueValue *src,
125135
assert(copyKind == ArrayCopy::BackToFront);
126136
assert(count != 0);
127137

128-
if (self->hasLayoutString() && destOp == ArrayDest::Init && srcOp == ArraySource::Copy) {
129-
return swift_generic_arrayInitWithCopy(dest, src, count, stride, self);
130-
}
131-
132138
auto copy = get_witness_function<destOp, srcOp>(wtable);
133139
size_t i = count;
134140
do {

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,19 @@ swift_generic_assignWithCopy(swift::OpaqueValue *dest, swift::OpaqueValue *src,
18321832
return dest;
18331833
}
18341834

1835+
void swift::swift_generic_arrayAssignWithCopy(swift::OpaqueValue *dest,
1836+
swift::OpaqueValue *src,
1837+
size_t count, size_t stride,
1838+
const Metadata *metadata) {
1839+
const uint8_t *layoutStr = metadata->getLayoutString();
1840+
for (size_t i = 0; i < count; i++) {
1841+
LayoutStringReader1 reader{layoutStr + layoutStringHeaderSize};
1842+
uintptr_t addrOffset = i * stride;
1843+
handleRefCountsAssignWithCopy(metadata, reader, addrOffset, (uint8_t *)dest,
1844+
(uint8_t *)src);
1845+
}
1846+
}
1847+
18351848
extern "C" swift::OpaqueValue *
18361849
swift_generic_assignWithTake(swift::OpaqueValue *dest, swift::OpaqueValue *src,
18371850
const Metadata *metadata) {

stdlib/public/runtime/BytecodeLayouts.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@ void swift_generic_arrayInitWithCopy(swift::OpaqueValue *dest,
245245
size_t stride,
246246
const Metadata *metadata);
247247

248+
void swift_generic_arrayAssignWithCopy(swift::OpaqueValue *dest,
249+
swift::OpaqueValue *src, size_t count,
250+
size_t stride, const Metadata *metadata);
251+
248252
constexpr size_t layoutStringHeaderSize = sizeof(uint64_t) + sizeof(size_t);
249253

250254
} // namespace swift

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ public struct Simple {
3939
}
4040
}
4141

42+
public struct GenericStruct<T> {
43+
let x: Int = 0
44+
let y: T
45+
46+
public init(_ y: T) {
47+
self.y = y
48+
}
49+
}
50+
4251
public class GenericClass<T> {
4352
let x: T
4453

@@ -637,3 +646,18 @@ public func testGenericDestroy<T>(_ ptr: __owned UnsafeMutableRawPointer, of tpe
637646
let ptr = ptr.assumingMemoryBound(to: InternalGeneric<T>.self)
638647
testDestroy(ptr)
639648
}
649+
650+
@inline(never)
651+
public func testGenericArrayDestroy<T>(_ buffer: UnsafeMutableBufferPointer<T>) {
652+
buffer.deinitialize()
653+
}
654+
655+
@inline(never)
656+
public func testGenericArrayInitWithCopy<T>(dest: UnsafeMutableBufferPointer<T>, src: UnsafeMutableBufferPointer<T>) {
657+
dest.initialize(fromContentsOf: src)
658+
}
659+
660+
@inline(never)
661+
public func testGenericArrayAssignWithCopy<T>(dest: UnsafeMutableBufferPointer<T>, src: UnsafeMutableBufferPointer<T>) {
662+
dest.update(fromContentsOf: src)
663+
}

test/Interpreter/layout_string_witnesses_dynamic.swift

Lines changed: 90 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,31 +1059,104 @@ func testSinglePayloadSimpleResolve() {
10591059

10601060
testSinglePayloadSimpleResolve()
10611061

1062-
// This is a regression test for rdar://118366415
1063-
func testTupleAlignment() {
1064-
let ptr = allocateInternalGenericPtr(of: TupleLargeAlignment<TestClass>.self)
1062+
func testArrayDestroy() {
1063+
let buffer = UnsafeMutableBufferPointer<GenericStruct<SimpleClass>>.allocate(capacity: 20)
10651064

1066-
do {
1067-
let x = TupleLargeAlignment(TestClass())
1068-
testGenericInit(ptr, to: x)
1065+
defer {
1066+
buffer.deallocate()
10691067
}
10701068

1071-
do {
1072-
let y = TupleLargeAlignment(TestClass())
1073-
// CHECK: Before deinit
1074-
print("Before deinit")
1069+
buffer.initialize(repeating: GenericStruct(SimpleClass(x: 23)))
10751070

1076-
// CHECK-NEXT: TestClass deinitialized!
1077-
testGenericAssign(ptr, from: y)
1071+
// CHECK: Before destroy
1072+
print("Before destroy")
1073+
// CHECK-NEXT: SimpleClass deinitialized!
1074+
testGenericArrayDestroy(buffer)
1075+
}
1076+
1077+
testArrayDestroy()
1078+
1079+
func testArrayInitWithCopy() {
1080+
let src = UnsafeMutableBufferPointer<GenericStruct<SimpleClass>>.allocate(capacity: 20)
1081+
let dest = UnsafeMutableBufferPointer<GenericStruct<SimpleClass>>.allocate(capacity: 20)
1082+
1083+
defer {
1084+
src.deallocate()
1085+
dest.deallocate()
10781086
}
10791087

1080-
// CHECK-NEXT: Before deinit
1081-
print("Before deinit")
1088+
src.initialize(repeating: GenericStruct(SimpleClass(x: 23)))
10821089

1083-
// CHECK-NEXT: TestClass deinitialized!
1084-
testGenericDestroy(ptr, of: TupleLargeAlignment<TestClass>.self)
1090+
testGenericArrayInitWithCopy(dest: dest, src: src)
10851091

1086-
ptr.deallocate()
1092+
// CHECK: Before src deinit
1093+
print("Before src deinit")
1094+
src.deinitialize()
1095+
1096+
// CHECK-NEXT: Before dest deinit
1097+
print("Before dest deinit")
1098+
1099+
// CHECK-NEXT: SimpleClass deinitialized!
1100+
dest.deinitialize()
1101+
}
1102+
1103+
testArrayInitWithCopy()
1104+
1105+
func testArrayAssignWithCopy() {
1106+
let src = UnsafeMutableBufferPointer<GenericStruct<SimpleClass>>.allocate(capacity: 20)
1107+
let dest = UnsafeMutableBufferPointer<GenericStruct<SimpleClass>>.allocate(capacity: 20)
1108+
1109+
defer {
1110+
src.deallocate()
1111+
dest.deallocate()
1112+
}
1113+
1114+
src.initialize(repeating: GenericStruct(SimpleClass(x: 23)))
1115+
dest.initialize(repeating: GenericStruct(SimpleClass(x: 32)))
1116+
1117+
// CHECK: Before assign
1118+
print("Before assign")
1119+
// CHECK-NEXT: SimpleClass deinitialized!
1120+
testGenericArrayAssignWithCopy(dest: dest, src: src)
1121+
1122+
// CHECK: Before src deinit
1123+
print("Before src deinit")
1124+
src.deinitialize()
1125+
1126+
// CHECK-NEXT: Before dest deinit
1127+
print("Before dest deinit")
1128+
1129+
// CHECK-NEXT: SimpleClass deinitialized!
1130+
dest.deinitialize()
1131+
}
1132+
1133+
testArrayAssignWithCopy()
1134+
1135+
// This is a regression test for rdar://118366415
1136+
func testTupleAlignment() {
1137+
let ptr = allocateInternalGenericPtr(of: TupleLargeAlignment<TestClass>.self)
1138+
1139+
do {
1140+
let x = TupleLargeAlignment(TestClass())
1141+
testGenericInit(ptr, to: x)
1142+
}
1143+
1144+
do {
1145+
let y = TupleLargeAlignment(TestClass())
1146+
// CHECK: Before deinit
1147+
print("Before deinit")
1148+
1149+
// CHECK-NEXT: TestClass deinitialized!
1150+
testGenericAssign(ptr, from: y)
1151+
}
1152+
1153+
// CHECK-NEXT: Before deinit
1154+
print("Before deinit")
1155+
1156+
// CHECK-NEXT: TestClass deinitialized!
1157+
testGenericDestroy(ptr, of: TupleLargeAlignment<TestClass>.self)
1158+
1159+
ptr.deallocate()
10871160
}
10881161

10891162
testTupleAlignment()

0 commit comments

Comments
 (0)