Skip to content

Commit d74c085

Browse files
authored
[Runtime+IRGen] Add layout string support for generic singleton enums (#66647)
1 parent adaa892 commit d74c085

File tree

9 files changed

+163
-34
lines changed

9 files changed

+163
-34
lines changed

include/swift/Runtime/Enum.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ void swift_initEnumMetadataSingleCase(EnumMetadata *enumType,
4545
EnumLayoutFlags flags,
4646
const TypeLayout *payload);
4747

48+
SWIFT_RUNTIME_EXPORT
49+
void swift_initEnumMetadataSingleCaseWithLayoutString(
50+
EnumMetadata *self, EnumLayoutFlags layoutFlags,
51+
const Metadata *payloadType);
52+
4853
/// Initialize the type metadata for a single-payload enum type.
4954
///
5055
/// \param enumType - pointer to the instantiated but uninitialized metadata

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,17 @@ FUNCTION(InitEnumMetadataSingleCase,
13001300
ATTRS(NoUnwind, WillReturn),
13011301
EFFECT(MetaData))
13021302

1303+
// void swift_initEnumMetadataSingleCaseWithLayoutString(Metadata *enumType,
1304+
// EnumLayoutFlags flags,
1305+
// Metadata *payload);
1306+
FUNCTION(InitEnumMetadataSingleCaseWithLayoutString,
1307+
swift_initEnumMetadataSingleCaseWithLayoutString,
1308+
C_CC, AlwaysAvailable,
1309+
RETURNS(VoidTy),
1310+
ARGS(TypeMetadataPtrTy, SizeTy, TypeMetadataPtrTy),
1311+
ATTRS(NoUnwind, WillReturn),
1312+
EFFECT(MetaData))
1313+
13031314
// void swift_initEnumMetadataSinglePayload(Metadata *enumType,
13041315
// EnumLayoutFlags flags,
13051316
// TypeLayout *payload,

lib/IRGen/GenEnum.cpp

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -663,13 +663,42 @@ namespace {
663663
metadata);
664664
}
665665

666-
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
667-
llvm::Value *metadata,
668-
bool isVWTMutable,
669-
SILType T,
670-
MetadataDependencyCollector *collector) const override {
671-
// Not yet supported on this type, so forward to regular method
672-
initializeMetadata(IGF, metadata, isVWTMutable, T, collector);
666+
void initializeMetadataWithLayoutString(
667+
IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T,
668+
MetadataDependencyCollector *collector) const override {
669+
if (TIK >= Fixed)
670+
return;
671+
672+
assert(ElementsWithPayload.size() == 1 &&
673+
"empty singleton enum should not be dynamic!");
674+
675+
auto payloadTy =
676+
T.getEnumElementType(ElementsWithPayload[0].decl, IGM.getSILModule(),
677+
IGM.getMaximalTypeExpansionContext());
678+
679+
auto request = DynamicMetadataRequest::getNonBlocking(
680+
MetadataState::LayoutComplete, collector);
681+
auto payloadMetadata =
682+
IGF.emitTypeMetadataRefForLayout(payloadTy, request);
683+
684+
auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
685+
IGF.Builder.CreateCall(
686+
IGF.IGM
687+
.getInitEnumMetadataSingleCaseWithLayoutStringFunctionPointer(),
688+
{metadata, flags, payloadMetadata});
689+
690+
// Pre swift-5.1 runtimes were missing the initialization of the
691+
// the extraInhabitantCount field. Do it here instead.
692+
auto payloadLayout = emitTypeLayoutRef(IGF, payloadTy, collector);
693+
auto payloadRef = IGF.Builder.CreateBitOrPointerCast(
694+
payloadLayout, IGF.IGM.TypeLayoutTy->getPointerTo());
695+
auto payloadExtraInhabitantCount =
696+
IGF.Builder.CreateLoad(IGF.Builder.CreateStructGEP(
697+
Address(payloadRef, IGF.IGM.TypeLayoutTy, Alignment(1)), 3,
698+
Size(IGF.IGM.DataLayout.getTypeAllocSize(IGF.IGM.SizeTy) * 2 +
699+
IGF.IGM.DataLayout.getTypeAllocSize(IGF.IGM.Int32Ty))));
700+
emitStoreOfExtraInhabitantCount(IGF, payloadExtraInhabitantCount,
701+
metadata);
673702
}
674703

675704
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
@@ -973,11 +1002,9 @@ namespace {
9731002
// witness table initialization.
9741003
}
9751004

976-
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
977-
llvm::Value *metadata,
978-
bool isVWTMutable,
979-
SILType T,
980-
MetadataDependencyCollector *collector) const override {
1005+
void initializeMetadataWithLayoutString(
1006+
IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T,
1007+
MetadataDependencyCollector *collector) const override {
9811008
// No-payload enums are always fixed-size so never need dynamic value
9821009
// witness table initialization.
9831010
}
@@ -3207,11 +3234,9 @@ namespace {
32073234
{metadata, flags, payloadLayout, emptyCasesVal});
32083235
}
32093236

3210-
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
3211-
llvm::Value *metadata,
3212-
bool isVWTMutable,
3213-
SILType T,
3214-
MetadataDependencyCollector *collector) const override {
3237+
void initializeMetadataWithLayoutString(
3238+
IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T,
3239+
MetadataDependencyCollector *collector) const override {
32153240
// Not yet supported on this type, so forward to regular method
32163241
initializeMetadata(IGF, metadata, isVWTMutable, T, collector);
32173242
}
@@ -5335,11 +5360,9 @@ namespace {
53355360
{metadata, flags, numPayloadsVal, payloadLayoutArray});
53365361
}
53375362

5338-
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
5339-
llvm::Value *metadata,
5340-
bool isVWTMutable,
5341-
SILType T,
5342-
MetadataDependencyCollector *collector) const override {
5363+
void initializeMetadataWithLayoutString(
5364+
IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T,
5365+
MetadataDependencyCollector *collector) const override {
53435366
// Fixed-size enums don't need dynamic metadata initialization.
53445367
if (TIK >= Fixed) return;
53455368

@@ -6035,11 +6058,9 @@ namespace {
60356058
llvm_unreachable("resilient enums cannot be defined");
60366059
}
60376060

6038-
void initializeMetadataWithLayoutString(IRGenFunction &IGF,
6039-
llvm::Value *metadata,
6040-
bool isVWTMutable,
6041-
SILType T,
6042-
MetadataDependencyCollector *collector) const override {
6061+
void initializeMetadataWithLayoutString(
6062+
IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T,
6063+
MetadataDependencyCollector *collector) const override {
60436064
llvm_unreachable("resilient enums cannot be defined");
60446065
}
60456066

lib/IRGen/GenMeta.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5737,14 +5737,17 @@ namespace {
57375737
}
57385738

57395739
auto &strategy = getEnumImplStrategy(IGM, getLoweredType());
5740+
bool isSupportedCase = strategy.getElementsWithPayload().size() > 1 ||
5741+
(strategy.getElementsWithPayload().size() == 1 &&
5742+
strategy.getElementsWithNoPayload().empty());
57405743

57415744
return !!getLayoutString() ||
57425745
(IGM.Context.LangOpts.hasFeature(
5743-
Feature::LayoutStringValueWitnessesInstantiation) &&
5746+
Feature::LayoutStringValueWitnessesInstantiation) &&
57445747
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation &&
5745-
(HasDependentVWT || HasDependentMetadata) &&
5746-
!isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())) &&
5747-
strategy.getElementsWithPayload().size() > 1);
5748+
(HasDependentVWT || HasDependentMetadata) &&
5749+
!isa<FixedTypeInfo>(IGM.getTypeInfo(getLoweredType())) &&
5750+
isSupportedCase);
57485751
}
57495752

57505753
llvm::Constant *emitNominalTypeDescriptor() {

lib/IRGen/GenValueWitness.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ bool isRuntimeInstatiatedLayoutString(IRGenModule &IGM,
892892
Feature::LayoutStringValueWitnessesInstantiation) &&
893893
IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation) {
894894
if (auto *enumEntry = typeLayoutEntry->getAsEnum()) {
895-
return enumEntry->isMultiPayloadEnum();
895+
return enumEntry->isMultiPayloadEnum() || enumEntry->isSingleton();
896896
}
897897
return (typeLayoutEntry->isAlignedGroup() &&
898898
!typeLayoutEntry->isFixedSize(IGM));

stdlib/public/runtime/Enum.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,61 @@ swift::swift_initEnumMetadataSingleCase(EnumMetadata *self,
6565
vwtable->publishLayout(layout);
6666
}
6767

68+
void swift::swift_initEnumMetadataSingleCaseWithLayoutString(
69+
EnumMetadata *self, EnumLayoutFlags layoutFlags,
70+
const Metadata *payloadType) {
71+
assert(self->hasLayoutString());
72+
73+
auto payloadLayout = payloadType->getTypeLayout();
74+
auto vwtable = getMutableVWTableForInit(self, layoutFlags);
75+
76+
TypeLayout layout;
77+
layout.size = payloadLayout->size;
78+
layout.stride = payloadLayout->stride;
79+
layout.flags = payloadLayout->flags.withEnumWitnesses(true);
80+
layout.extraInhabitantCount = payloadLayout->getNumExtraInhabitants();
81+
82+
auto refCountBytes = _swift_refCountBytesForMetatype(payloadType);
83+
const size_t fixedLayoutStringSize =
84+
layoutStringHeaderSize + sizeof(uint64_t) * 2;
85+
86+
uint8_t *layoutStr =
87+
(uint8_t *)MetadataAllocator(LayoutStringTag)
88+
.Allocate(fixedLayoutStringSize + refCountBytes, alignof(uint8_t));
89+
90+
size_t layoutStrOffset = sizeof(uint64_t);
91+
writeBytes(layoutStr, layoutStrOffset, refCountBytes);
92+
size_t fullOffset = 0;
93+
size_t previousFieldOffset = 0;
94+
LayoutStringFlags flags = LayoutStringFlags::Empty;
95+
96+
_swift_addRefCountStringForMetatype(layoutStr, layoutStrOffset, flags,
97+
payloadType, fullOffset,
98+
previousFieldOffset);
99+
100+
writeBytes(layoutStr, layoutStrOffset, (uint64_t)previousFieldOffset);
101+
writeBytes(layoutStr, layoutStrOffset, (uint64_t)0);
102+
103+
// we mask out HasRelativePointers, because at this point they have all been
104+
// resolved to metadata pointers
105+
layoutStrOffset = 0;
106+
writeBytes(layoutStr, layoutStrOffset,
107+
((uint64_t)flags) &
108+
~((uint64_t)LayoutStringFlags::HasRelativePointers));
109+
110+
vwtable->destroy = swift_generic_destroy;
111+
vwtable->initializeWithCopy = swift_generic_initWithCopy;
112+
vwtable->initializeWithTake = swift_generic_initWithTake;
113+
vwtable->assignWithCopy = swift_generic_assignWithCopy;
114+
vwtable->assignWithTake = swift_generic_assignWithTake;
115+
116+
installCommonValueWitnesses(layout, vwtable);
117+
118+
self->setLayoutString(layoutStr);
119+
120+
vwtable->publishLayout(layout);
121+
}
122+
68123
void
69124
swift::swift_initEnumMetadataSinglePayload(EnumMetadata *self,
70125
EnumLayoutFlags layoutFlags,
@@ -221,6 +276,8 @@ void swift::swift_initEnumMetadataMultiPayloadWithLayoutString(
221276
EnumLayoutFlags layoutFlags,
222277
unsigned numPayloads,
223278
const Metadata * const *payloadLayouts) {
279+
assert(enumType->hasLayoutString());
280+
224281
// Accumulate the layout requirements of the payloads.
225282
size_t payloadSize = 0, alignMask = 0;
226283
bool isPOD = true, isBT = true;

stdlib/public/runtime/Metadata.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2750,8 +2750,8 @@ void swift::swift_initStructMetadataWithLayoutString(
27502750
previousFieldOffset);
27512751
}
27522752

2753-
writeBytes(layoutStr, layoutStrOffset, previousFieldOffset);
2754-
writeBytes(layoutStr, layoutStrOffset, 0);
2753+
writeBytes(layoutStr, layoutStrOffset, (uint64_t)previousFieldOffset);
2754+
writeBytes(layoutStr, layoutStrOffset, (uint64_t)0);
27552755

27562756
// we mask out HasRelativePointers, because at this point they have all been
27572757
// resolved to metadata pointers

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,10 @@ public struct InternalEnumWrapper {
442442
}
443443
}
444444

445+
public enum SingletonEnum<T> {
446+
case only(T, Int)
447+
}
448+
445449
public enum SinglePayloadEnumManyXI {
446450
case empty0
447451
case empty1

test/Interpreter/layout_string_witnesses_dynamic.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,34 @@ func testGenericEnum() {
243243

244244
testGenericEnum()
245245

246+
func testGenericEnumSingleton() {
247+
let ptr = allocateInternalGenericPtr(of: SingletonEnum<TestClass>.self)
248+
249+
do {
250+
let x = TestClass()
251+
testGenericInit(ptr, to: SingletonEnum<TestClass>.only(x, 23))
252+
}
253+
254+
do {
255+
let y = TestClass()
256+
// CHECK: Before deinit
257+
print("Before deinit")
258+
259+
// CHECK-NEXT: TestClass deinitialized!
260+
testGenericAssign(ptr, from: SingletonEnum<TestClass>.only(y, 32))
261+
}
262+
263+
// CHECK-NEXT: Before deinit
264+
print("Before deinit")
265+
266+
// CHECK-NEXT: TestClass deinitialized!
267+
testGenericDestroy(ptr, of: SingletonEnum<TestClass>.self)
268+
269+
ptr.deallocate()
270+
}
271+
272+
testGenericEnumSingleton()
273+
246274
func testRecursive() {
247275
let ptr = allocateInternalGenericPtr(of: Recursive<TestClass>.self)
248276

0 commit comments

Comments
 (0)