diff --git a/include/swift/Runtime/Enum.h b/include/swift/Runtime/Enum.h index 21d8b4901b369..4eaa6c8ac2032 100644 --- a/include/swift/Runtime/Enum.h +++ b/include/swift/Runtime/Enum.h @@ -45,6 +45,11 @@ void swift_initEnumMetadataSingleCase(EnumMetadata *enumType, EnumLayoutFlags flags, const TypeLayout *payload); +SWIFT_RUNTIME_EXPORT +void swift_initEnumMetadataSingleCaseWithLayoutString( + EnumMetadata *self, EnumLayoutFlags layoutFlags, + const Metadata *payloadType); + /// Initialize the type metadata for a single-payload enum type. /// /// \param enumType - pointer to the instantiated but uninitialized metadata diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 8ab6e20a1d147..0d88cd1258647 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -1300,6 +1300,17 @@ FUNCTION(InitEnumMetadataSingleCase, ATTRS(NoUnwind, WillReturn), EFFECT(MetaData)) +// void swift_initEnumMetadataSingleCaseWithLayoutString(Metadata *enumType, +// EnumLayoutFlags flags, +// Metadata *payload); +FUNCTION(InitEnumMetadataSingleCaseWithLayoutString, + swift_initEnumMetadataSingleCaseWithLayoutString, + C_CC, AlwaysAvailable, + RETURNS(VoidTy), + ARGS(TypeMetadataPtrTy, SizeTy, TypeMetadataPtrTy), + ATTRS(NoUnwind, WillReturn), + EFFECT(MetaData)) + // void swift_initEnumMetadataSinglePayload(Metadata *enumType, // EnumLayoutFlags flags, // TypeLayout *payload, diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index 42542c7e3c240..18f1f7f28f4ad 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -663,13 +663,42 @@ namespace { metadata); } - void initializeMetadataWithLayoutString(IRGenFunction &IGF, - llvm::Value *metadata, - bool isVWTMutable, - SILType T, - MetadataDependencyCollector *collector) const override { - // Not yet supported on this type, so forward to regular method - initializeMetadata(IGF, metadata, isVWTMutable, T, collector); + void initializeMetadataWithLayoutString( + IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T, + MetadataDependencyCollector *collector) const override { + if (TIK >= Fixed) + return; + + assert(ElementsWithPayload.size() == 1 && + "empty singleton enum should not be dynamic!"); + + auto payloadTy = + T.getEnumElementType(ElementsWithPayload[0].decl, IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()); + + auto request = DynamicMetadataRequest::getNonBlocking( + MetadataState::LayoutComplete, collector); + auto payloadMetadata = + IGF.emitTypeMetadataRefForLayout(payloadTy, request); + + auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable); + IGF.Builder.CreateCall( + IGF.IGM + .getInitEnumMetadataSingleCaseWithLayoutStringFunctionPointer(), + {metadata, flags, payloadMetadata}); + + // Pre swift-5.1 runtimes were missing the initialization of the + // the extraInhabitantCount field. Do it here instead. + auto payloadLayout = emitTypeLayoutRef(IGF, payloadTy, collector); + auto payloadRef = IGF.Builder.CreateBitOrPointerCast( + payloadLayout, IGF.IGM.TypeLayoutTy->getPointerTo()); + auto payloadExtraInhabitantCount = + IGF.Builder.CreateLoad(IGF.Builder.CreateStructGEP( + Address(payloadRef, IGF.IGM.TypeLayoutTy, Alignment(1)), 3, + Size(IGF.IGM.DataLayout.getTypeAllocSize(IGF.IGM.SizeTy) * 2 + + IGF.IGM.DataLayout.getTypeAllocSize(IGF.IGM.Int32Ty)))); + emitStoreOfExtraInhabitantCount(IGF, payloadExtraInhabitantCount, + metadata); } bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { @@ -973,11 +1002,9 @@ namespace { // witness table initialization. } - void initializeMetadataWithLayoutString(IRGenFunction &IGF, - llvm::Value *metadata, - bool isVWTMutable, - SILType T, - MetadataDependencyCollector *collector) const override { + void initializeMetadataWithLayoutString( + IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T, + MetadataDependencyCollector *collector) const override { // No-payload enums are always fixed-size so never need dynamic value // witness table initialization. } @@ -3207,11 +3234,9 @@ namespace { {metadata, flags, payloadLayout, emptyCasesVal}); } - void initializeMetadataWithLayoutString(IRGenFunction &IGF, - llvm::Value *metadata, - bool isVWTMutable, - SILType T, - MetadataDependencyCollector *collector) const override { + void initializeMetadataWithLayoutString( + IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T, + MetadataDependencyCollector *collector) const override { // Not yet supported on this type, so forward to regular method initializeMetadata(IGF, metadata, isVWTMutable, T, collector); } @@ -5335,11 +5360,9 @@ namespace { {metadata, flags, numPayloadsVal, payloadLayoutArray}); } - void initializeMetadataWithLayoutString(IRGenFunction &IGF, - llvm::Value *metadata, - bool isVWTMutable, - SILType T, - MetadataDependencyCollector *collector) const override { + void initializeMetadataWithLayoutString( + IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T, + MetadataDependencyCollector *collector) const override { // Fixed-size enums don't need dynamic metadata initialization. if (TIK >= Fixed) return; @@ -6035,11 +6058,9 @@ namespace { llvm_unreachable("resilient enums cannot be defined"); } - void initializeMetadataWithLayoutString(IRGenFunction &IGF, - llvm::Value *metadata, - bool isVWTMutable, - SILType T, - MetadataDependencyCollector *collector) const override { + void initializeMetadataWithLayoutString( + IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, SILType T, + MetadataDependencyCollector *collector) const override { llvm_unreachable("resilient enums cannot be defined"); } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index c46a4dac25f22..3a67800eb009e 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -5737,14 +5737,17 @@ namespace { } auto &strategy = getEnumImplStrategy(IGM, getLoweredType()); + bool isSupportedCase = strategy.getElementsWithPayload().size() > 1 || + (strategy.getElementsWithPayload().size() == 1 && + strategy.getElementsWithNoPayload().empty()); return !!getLayoutString() || (IGM.Context.LangOpts.hasFeature( - Feature::LayoutStringValueWitnessesInstantiation) && + Feature::LayoutStringValueWitnessesInstantiation) && IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation && - (HasDependentVWT || HasDependentMetadata) && - !isa(IGM.getTypeInfo(getLoweredType())) && - strategy.getElementsWithPayload().size() > 1); + (HasDependentVWT || HasDependentMetadata) && + !isa(IGM.getTypeInfo(getLoweredType())) && + isSupportedCase); } llvm::Constant *emitNominalTypeDescriptor() { diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp index 886297dd948a3..fb9693e6857d2 100644 --- a/lib/IRGen/GenValueWitness.cpp +++ b/lib/IRGen/GenValueWitness.cpp @@ -892,7 +892,7 @@ bool isRuntimeInstatiatedLayoutString(IRGenModule &IGM, Feature::LayoutStringValueWitnessesInstantiation) && IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation) { if (auto *enumEntry = typeLayoutEntry->getAsEnum()) { - return enumEntry->isMultiPayloadEnum(); + return enumEntry->isMultiPayloadEnum() || enumEntry->isSingleton(); } return (typeLayoutEntry->isAlignedGroup() && !typeLayoutEntry->isFixedSize(IGM)); diff --git a/stdlib/public/runtime/Enum.cpp b/stdlib/public/runtime/Enum.cpp index 13c00ed9dcc97..38c4b316f19ab 100644 --- a/stdlib/public/runtime/Enum.cpp +++ b/stdlib/public/runtime/Enum.cpp @@ -65,6 +65,61 @@ swift::swift_initEnumMetadataSingleCase(EnumMetadata *self, vwtable->publishLayout(layout); } +void swift::swift_initEnumMetadataSingleCaseWithLayoutString( + EnumMetadata *self, EnumLayoutFlags layoutFlags, + const Metadata *payloadType) { + assert(self->hasLayoutString()); + + auto payloadLayout = payloadType->getTypeLayout(); + auto vwtable = getMutableVWTableForInit(self, layoutFlags); + + TypeLayout layout; + layout.size = payloadLayout->size; + layout.stride = payloadLayout->stride; + layout.flags = payloadLayout->flags.withEnumWitnesses(true); + layout.extraInhabitantCount = payloadLayout->getNumExtraInhabitants(); + + auto refCountBytes = _swift_refCountBytesForMetatype(payloadType); + const size_t fixedLayoutStringSize = + layoutStringHeaderSize + sizeof(uint64_t) * 2; + + uint8_t *layoutStr = + (uint8_t *)MetadataAllocator(LayoutStringTag) + .Allocate(fixedLayoutStringSize + refCountBytes, alignof(uint8_t)); + + size_t layoutStrOffset = sizeof(uint64_t); + writeBytes(layoutStr, layoutStrOffset, refCountBytes); + size_t fullOffset = 0; + size_t previousFieldOffset = 0; + LayoutStringFlags flags = LayoutStringFlags::Empty; + + _swift_addRefCountStringForMetatype(layoutStr, layoutStrOffset, flags, + payloadType, fullOffset, + previousFieldOffset); + + writeBytes(layoutStr, layoutStrOffset, (uint64_t)previousFieldOffset); + writeBytes(layoutStr, layoutStrOffset, (uint64_t)0); + + // we mask out HasRelativePointers, because at this point they have all been + // resolved to metadata pointers + layoutStrOffset = 0; + writeBytes(layoutStr, layoutStrOffset, + ((uint64_t)flags) & + ~((uint64_t)LayoutStringFlags::HasRelativePointers)); + + vwtable->destroy = swift_generic_destroy; + vwtable->initializeWithCopy = swift_generic_initWithCopy; + vwtable->initializeWithTake = swift_generic_initWithTake; + vwtable->assignWithCopy = swift_generic_assignWithCopy; + vwtable->assignWithTake = swift_generic_assignWithTake; + + installCommonValueWitnesses(layout, vwtable); + + self->setLayoutString(layoutStr); + + vwtable->publishLayout(layout); +} + void swift::swift_initEnumMetadataSinglePayload(EnumMetadata *self, EnumLayoutFlags layoutFlags, @@ -221,6 +276,8 @@ void swift::swift_initEnumMetadataMultiPayloadWithLayoutString( EnumLayoutFlags layoutFlags, unsigned numPayloads, const Metadata * const *payloadLayouts) { + assert(enumType->hasLayoutString()); + // Accumulate the layout requirements of the payloads. size_t payloadSize = 0, alignMask = 0; bool isPOD = true, isBT = true; diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 9a91f5a23874d..9d32c266b8ba2 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -2739,8 +2739,8 @@ void swift::swift_initStructMetadataWithLayoutString( previousFieldOffset); } - writeBytes(layoutStr, layoutStrOffset, previousFieldOffset); - writeBytes(layoutStr, layoutStrOffset, 0); + writeBytes(layoutStr, layoutStrOffset, (uint64_t)previousFieldOffset); + writeBytes(layoutStr, layoutStrOffset, (uint64_t)0); // we mask out HasRelativePointers, because at this point they have all been // resolved to metadata pointers diff --git a/test/Interpreter/Inputs/layout_string_witnesses_types.swift b/test/Interpreter/Inputs/layout_string_witnesses_types.swift index 5847702ce5195..1eb45df5b93d2 100644 --- a/test/Interpreter/Inputs/layout_string_witnesses_types.swift +++ b/test/Interpreter/Inputs/layout_string_witnesses_types.swift @@ -442,6 +442,10 @@ public struct InternalEnumWrapper { } } +public enum SingletonEnum { + case only(T, Int) +} + public enum SinglePayloadEnumManyXI { case empty0 case empty1 diff --git a/test/Interpreter/layout_string_witnesses_dynamic.swift b/test/Interpreter/layout_string_witnesses_dynamic.swift index cf402abf8ef8c..3bf1c64fa382b 100644 --- a/test/Interpreter/layout_string_witnesses_dynamic.swift +++ b/test/Interpreter/layout_string_witnesses_dynamic.swift @@ -243,6 +243,34 @@ func testGenericEnum() { testGenericEnum() +func testGenericEnumSingleton() { + let ptr = allocateInternalGenericPtr(of: SingletonEnum.self) + + do { + let x = TestClass() + testGenericInit(ptr, to: SingletonEnum.only(x, 23)) + } + + do { + let y = TestClass() + // CHECK: Before deinit + print("Before deinit") + + // CHECK-NEXT: TestClass deinitialized! + testGenericAssign(ptr, from: SingletonEnum.only(y, 32)) + } + + // CHECK-NEXT: Before deinit + print("Before deinit") + + // CHECK-NEXT: TestClass deinitialized! + testGenericDestroy(ptr, of: SingletonEnum.self) + + ptr.deallocate() +} + +testGenericEnumSingleton() + func testRecursive() { let ptr = allocateInternalGenericPtr(of: Recursive.self)