Skip to content

Commit ca66414

Browse files
authored
[IRGen+Runtime] Add support for initializeBufferWithCopyOfBuffer to layout strings (#66965)
1 parent eec7231 commit ca66414

File tree

6 files changed

+128
-2
lines changed

6 files changed

+128
-2
lines changed

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2315,6 +2315,17 @@ FUNCTION(GenericInitWithTake,
23152315
ATTRS(NoUnwind),
23162316
EFFECT(Refcounting))
23172317

2318+
// void *swift_generic_initializeBufferWithCopyOfBuffer(ValueBuffer* dest, ValueBuffer* src, const Metadata* type);
2319+
FUNCTION(GenericInitializeBufferWithCopyOfBuffer,
2320+
swift_generic_initializeBufferWithCopyOfBuffer,
2321+
C_CC, AlwaysAvailable,
2322+
RETURNS(Int8PtrTy),
2323+
ARGS(getFixedBufferTy()->getPointerTo(),
2324+
getFixedBufferTy()->getPointerTo(),
2325+
TypeMetadataPtrTy),
2326+
ATTRS(NoUnwind),
2327+
EFFECT(Refcounting))
2328+
23182329
// unsigned swift_enumSimple_getEnumTag(swift::OpaqueValue *address,
23192330
// const Metadata *metadata);
23202331
FUNCTION(EnumSimpleGetEnumTag,

lib/IRGen/GenValueWitness.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,26 @@ addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B, ValueWitness index,
10121012
return addFunction(getInitWithCopyStrongFunction(IGM));
10131013
}
10141014
}
1015+
1016+
if (IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses) &&
1017+
IGM.getOptions().EnableLayoutStringValueWitnesses) {
1018+
auto ty = boundGenericCharacteristics
1019+
? boundGenericCharacteristics->concreteType
1020+
: concreteType;
1021+
auto &typeInfo = boundGenericCharacteristics
1022+
? *boundGenericCharacteristics->TI
1023+
: concreteTI;
1024+
if (auto *typeLayoutEntry = typeInfo.buildTypeLayoutEntry(
1025+
IGM, ty, /*useStructLayouts*/ true)) {
1026+
auto genericSig = concreteType.getNominalOrBoundGenericNominal()
1027+
->getGenericSignature();
1028+
if (typeLayoutEntry->layoutString(IGM, genericSig) ||
1029+
isRuntimeInstatiatedLayoutString(IGM, typeLayoutEntry)) {
1030+
return addFunction(
1031+
IGM.getGenericInitializeBufferWithCopyOfBufferFn());
1032+
}
1033+
}
1034+
}
10151035
goto standard;
10161036

10171037
case ValueWitness::InitializeWithTake:

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,20 @@ swift_singlePayloadEnumGeneric_getEnumTag(swift::OpaqueValue *address,
784784
return 0;
785785
}
786786

787+
extern "C" swift::OpaqueValue *
788+
swift_generic_initializeBufferWithCopyOfBuffer(swift::ValueBuffer *dest,
789+
swift::ValueBuffer *src,
790+
const Metadata *metadata) {
791+
if (metadata->getValueWitnesses()->isValueInline()) {
792+
return swift_generic_initWithCopy((swift::OpaqueValue *)dest,
793+
(swift::OpaqueValue *)src, metadata);
794+
} else {
795+
memcpy(dest, src, sizeof(swift::HeapObject *));
796+
swift_retain(*(swift::HeapObject **)src);
797+
return (swift::OpaqueValue *)&(*(swift::HeapObject **)dest)[1];
798+
}
799+
}
800+
787801
void swift::swift_resolve_resilientAccessors(uint8_t *layoutStr,
788802
size_t layoutStrOffset,
789803
const uint8_t *fieldLayoutStr,

stdlib/public/runtime/BytecodeLayouts.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ swift::OpaqueValue *swift_generic_initWithTake(swift::OpaqueValue *dest,
113113
swift::OpaqueValue *src,
114114
const Metadata *metadata);
115115
SWIFT_RUNTIME_EXPORT
116+
swift::OpaqueValue *
117+
swift_generic_initializeBufferWithCopyOfBuffer(swift::ValueBuffer *dest,
118+
swift::ValueBuffer *src,
119+
const Metadata *metadata);
120+
SWIFT_RUNTIME_EXPORT
116121
unsigned swift_enumSimple_getEnumTag(swift::OpaqueValue *address,
117122
const Metadata *metadata);
118123
SWIFT_RUNTIME_EXPORT

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ public struct ExistentialWrapper {
125125
}
126126
}
127127

128+
@inline(never)
129+
public func createExistentialWrapper(_ x: any SomeProtocol) -> ExistentialWrapper {
130+
return ExistentialWrapper(x: x)
131+
}
132+
128133
public protocol SomeClassProtocol: AnyObject {}
129134

130135
public struct ExistentialRefWrapper {

test/Interpreter/layout_string_witnesses_static.swift

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ class ClassWithSomeProtocol: SomeProtocol {
193193
}
194194
}
195195

196-
func testExistential() {
196+
func testExistentialClass() {
197197
let ptr = UnsafeMutablePointer<ExistentialWrapper>.allocate(capacity: 1)
198198

199199
do {
@@ -220,7 +220,78 @@ func testExistential() {
220220
ptr.deallocate()
221221
}
222222

223-
testExistential()
223+
testExistentialClass()
224+
225+
struct StructWithSomeProtocolInline: SomeProtocol {
226+
let y: Int = 0
227+
let x: SimpleClass
228+
}
229+
230+
func testExistentialStructInline() {
231+
let ptr = UnsafeMutablePointer<ExistentialWrapper>.allocate(capacity: 1)
232+
233+
do {
234+
let x = StructWithSomeProtocolInline(x: SimpleClass(x: 23))
235+
testInit(ptr, to: createExistentialWrapper(x))
236+
}
237+
238+
do {
239+
let y = StructWithSomeProtocolInline(x: SimpleClass(x: 32))
240+
241+
// CHECK: Before deinit
242+
print("Before deinit")
243+
244+
// CHECK-NEXT: SimpleClass deinitialized!
245+
testAssign(ptr, from: createExistentialWrapper(y))
246+
}
247+
248+
// CHECK-NEXT: Before deinit
249+
print("Before deinit")
250+
251+
// CHECK-NEXT: SimpleClass deinitialized!
252+
testDestroy(ptr)
253+
254+
ptr.deallocate()
255+
}
256+
257+
testExistentialStructInline()
258+
259+
struct StructWithSomeProtocolBox: SomeProtocol {
260+
let y: Int = 0
261+
let x: SimpleClass
262+
let z: Int = 0
263+
let zz: Int = 0
264+
let zzz: Int = 0
265+
}
266+
267+
func testExistentialStructBox() {
268+
let ptr = UnsafeMutablePointer<ExistentialWrapper>.allocate(capacity: 1)
269+
270+
do {
271+
let x = StructWithSomeProtocolBox(x: SimpleClass(x: 23))
272+
testInit(ptr, to: createExistentialWrapper(x))
273+
}
274+
275+
do {
276+
let y = StructWithSomeProtocolBox(x: SimpleClass(x: 32))
277+
278+
// CHECK: Before deinit
279+
print("Before deinit")
280+
281+
// CHECK-NEXT: SimpleClass deinitialized!
282+
testAssign(ptr, from: createExistentialWrapper(y))
283+
}
284+
285+
// CHECK-NEXT: Before deinit
286+
print("Before deinit")
287+
288+
// CHECK-NEXT: SimpleClass deinitialized!
289+
testDestroy(ptr)
290+
291+
ptr.deallocate()
292+
}
293+
294+
testExistentialStructBox()
224295

225296
class ClassWithSomeClassProtocol: SomeClassProtocol {
226297
deinit {

0 commit comments

Comments
 (0)