Skip to content

Commit 56d0975

Browse files
committed
[Runtime] Add layout string handling in swift_arrayAssignWithCopyFrontToBack
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 d6c67f6 commit 56d0975

File tree

5 files changed

+124
-4
lines changed

5 files changed

+124
-4
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
@@ -1827,6 +1827,19 @@ swift_generic_assignWithCopy(swift::OpaqueValue *dest, swift::OpaqueValue *src,
18271827
return dest;
18281828
}
18291829

1830+
void swift::swift_generic_arrayAssignWithCopy(swift::OpaqueValue *dest,
1831+
swift::OpaqueValue *src,
1832+
size_t count, size_t stride,
1833+
const Metadata *metadata) {
1834+
const uint8_t *layoutStr = metadata->getLayoutString();
1835+
for (size_t i = 0; i < count; i++) {
1836+
LayoutStringReader1 reader{layoutStr + layoutStringHeaderSize};
1837+
uintptr_t addrOffset = i * stride;
1838+
handleRefCountsAssignWithCopy(metadata, reader, addrOffset, (uint8_t *)dest,
1839+
(uint8_t *)src);
1840+
}
1841+
}
1842+
18301843
extern "C" swift::OpaqueValue *
18311844
swift_generic_assignWithTake(swift::OpaqueValue *dest, swift::OpaqueValue *src,
18321845
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

@@ -601,3 +610,18 @@ public func testGenericDestroy<T>(_ ptr: __owned UnsafeMutableRawPointer, of tpe
601610
let ptr = ptr.assumingMemoryBound(to: InternalGeneric<T>.self)
602611
testDestroy(ptr)
603612
}
613+
614+
@inline(never)
615+
public func testGenericArrayDestroy<T>(_ buffer: UnsafeMutableBufferPointer<T>) {
616+
buffer.deinitialize()
617+
}
618+
619+
@inline(never)
620+
public func testGenericArrayInitWithCopy<T>(dest: UnsafeMutableBufferPointer<T>, src: UnsafeMutableBufferPointer<T>) {
621+
dest.initialize(fromContentsOf: src)
622+
}
623+
624+
@inline(never)
625+
public func testGenericArrayAssignWithCopy<T>(dest: UnsafeMutableBufferPointer<T>, src: UnsafeMutableBufferPointer<T>) {
626+
dest.update(fromContentsOf: src)
627+
}

test/Interpreter/layout_string_witnesses_dynamic.swift

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,79 @@ func testSinglePayloadSimpleResolve() {
10591059

10601060
testSinglePayloadSimpleResolve()
10611061

1062+
func testArrayDestroy() {
1063+
let buffer = UnsafeMutableBufferPointer<GenericStruct<SimpleClass>>.allocate(capacity: 20)
1064+
1065+
defer {
1066+
buffer.deallocate()
1067+
}
1068+
1069+
buffer.initialize(repeating: GenericStruct(SimpleClass(x: 23)))
1070+
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()
1086+
}
1087+
1088+
src.initialize(repeating: GenericStruct(SimpleClass(x: 23)))
1089+
1090+
testGenericArrayInitWithCopy(dest: dest, src: src)
1091+
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+
10621135
#if os(macOS)
10631136

10641137
import Foundation

0 commit comments

Comments
 (0)