diff --git a/include/swift/Runtime/Enum.h b/include/swift/Runtime/Enum.h index 47cb97376e8d3..21d8b4901b369 100644 --- a/include/swift/Runtime/Enum.h +++ b/include/swift/Runtime/Enum.h @@ -111,6 +111,12 @@ void swift_initEnumMetadataMultiPayload(EnumMetadata *enumType, unsigned numPayloads, const TypeLayout * const *payloadTypes); +SWIFT_RUNTIME_EXPORT +void swift_initEnumMetadataMultiPayloadWithLayoutString(EnumMetadata *enumType, + EnumLayoutFlags flags, + unsigned numPayloads, + const Metadata * const *payloadTypes); + /// Return an integer value representing which case of a multi-payload /// enum is inhabited. /// diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 5a9690b13ae79..8ab6e20a1d147 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -1276,7 +1276,8 @@ FUNCTION(InitStructMetadata, // void swift_initStructMetadataWithLayoutString(Metadata *structType, // StructLayoutFlags flags, // size_t numFields, -// Metadata * const *fieldTypes, +// uint8_t * const *fieldTypes, +// const uint8_t *fieldTags // uint32_t *fieldOffsets); FUNCTION(InitStructMetadataWithLayoutString, swift_initStructMetadataWithLayoutString, C_CC, AlwaysAvailable, @@ -1312,6 +1313,7 @@ FUNCTION(InitEnumMetadataSinglePayload, EFFECT(MetaData)) // void swift_initEnumMetadataMultiPayload(Metadata *enumType, +// EnumLayoutFlags layoutFlags, // size_t numPayloads, // TypeLayout * const *payloadTypes); FUNCTION(InitEnumMetadataMultiPayload, @@ -1322,6 +1324,19 @@ FUNCTION(InitEnumMetadataMultiPayload, ATTRS(NoUnwind, WillReturn), EFFECT(MetaData)) +// void +// swift_initEnumMetadataMultiPayloadWithLayoutString(Metadata *enumType, +// EnumLayoutFlags layoutFlags, +// size_t numPayloads, +// Metadata * const *payloadTypes); +FUNCTION(InitEnumMetadataMultiPayloadWithLayoutString, + swift_initEnumMetadataMultiPayloadWithLayoutString, + C_CC, AlwaysAvailable, + RETURNS(VoidTy), + ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, TypeMetadataPtrPtrTy), + ATTRS(NoUnwind, WillReturn), + EFFECT(MetaData)) + // int swift_getEnumCaseMultiPayload(opaque_t *obj, Metadata *enumTy); FUNCTION(GetEnumCaseMultiPayload, swift_getEnumCaseMultiPayload, diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index bf4c6b16f374d..42542c7e3c240 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -663,6 +663,15 @@ 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); + } + bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { // FIXME: Hold off on registering extra inhabitants for dynamic enums // until initializeMetadata handles them. @@ -964,6 +973,15 @@ namespace { // witness table initialization. } + 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. + } + /// \group Required for SingleScalarTypeInfo llvm::Type *getScalarType() const { @@ -3189,6 +3207,15 @@ namespace { {metadata, flags, payloadLayout, emptyCasesVal}); } + 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); + } + /// \group Extra inhabitants // Extra inhabitants from the payload that we didn't use for our empty cases @@ -5259,6 +5286,36 @@ namespace { return firstAddr; } + llvm::Value *emitPayloadMetadataArray(IRGenFunction &IGF, SILType T, + MetadataDependencyCollector *collector) const { + auto numPayloads = ElementsWithPayload.size(); + auto metadataBufferTy = llvm::ArrayType::get(IGM.TypeMetadataPtrTy, + numPayloads); + auto metadataBuffer = IGF.createAlloca(metadataBufferTy, + IGM.getPointerAlignment(), + "payload_types"); + llvm::Value *firstAddr = nullptr; + for (unsigned i = 0; i < numPayloads; ++i) { + auto &elt = ElementsWithPayload[i]; + Address eltAddr = IGF.Builder.CreateStructGEP(metadataBuffer, i, + IGM.getPointerSize() * i); + if (i == 0) firstAddr = eltAddr.getAddress(); + + auto payloadTy = + T.getEnumElementType(elt.decl, IGF.getSILModule(), + IGF.IGM.getMaximalTypeExpansionContext()); + + auto request = DynamicMetadataRequest::getNonBlocking( + MetadataState::LayoutComplete, collector); + auto metadata = IGF.emitTypeMetadataRefForLayout(payloadTy, request); + + IGF.Builder.CreateStore(metadata, eltAddr); + } + assert(firstAddr && "Expected firstAddr to be assigned to"); + + return firstAddr; + } + void initializeMetadata(IRGenFunction &IGF, llvm::Value *metadata, bool isVWTMutable, @@ -5278,6 +5335,25 @@ namespace { {metadata, flags, numPayloadsVal, payloadLayoutArray}); } + 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; + + // Ask the runtime to set up the metadata record for a dynamic enum. + auto payloadLayoutArray = emitPayloadMetadataArray(IGF, T, collector); + auto numPayloadsVal = llvm::ConstantInt::get(IGM.SizeTy, + ElementsWithPayload.size()); + + auto flags = emitEnumLayoutFlags(IGM, isVWTMutable); + IGF.Builder.CreateCall( + IGM.getInitEnumMetadataMultiPayloadWithLayoutStringFunctionPointer(), + {metadata, flags, numPayloadsVal, payloadLayoutArray}); + } + /// \group Extra inhabitants // If we didn't use all of the available tag bit representations, offer @@ -5959,6 +6035,14 @@ namespace { llvm_unreachable("resilient enums cannot be defined"); } + void initializeMetadataWithLayoutString(IRGenFunction &IGF, + llvm::Value *metadata, + bool isVWTMutable, + SILType T, + MetadataDependencyCollector *collector) const override { + llvm_unreachable("resilient enums cannot be defined"); + } + /// \group Extra inhabitants bool mayHaveExtraInhabitants(IRGenModule &) const override { diff --git a/lib/IRGen/GenEnum.h b/lib/IRGen/GenEnum.h index c0ecbae1c3205..53f35c47c4311 100644 --- a/lib/IRGen/GenEnum.h +++ b/lib/IRGen/GenEnum.h @@ -384,6 +384,12 @@ class EnumImplStrategy { SILType T, MetadataDependencyCollector *collector) const = 0; + virtual void initializeMetadataWithLayoutString(IRGenFunction &IGF, + llvm::Value *metadata, + bool isVWTMutable, + SILType T, + MetadataDependencyCollector *collector) const = 0; + virtual bool mayHaveExtraInhabitants(IRGenModule &IGM) const = 0; // Only ever called for fixed types. diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index f8bb678447849..c46a4dac25f22 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -3003,16 +3003,17 @@ static void emitInitializeValueMetadata(IRGenFunction &IGF, MetadataDependencyCollector *collector) { auto &IGM = IGF.IGM; auto loweredTy = IGM.getLoweredType(nominalDecl->getDeclaredTypeInContext()); + bool useLayoutStrings = IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses) && + IGM.Context.LangOpts.hasFeature( + Feature::LayoutStringValueWitnessesInstantiation) && + IGM.getOptions().EnableLayoutStringValueWitnesses && + IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation; if (isa(nominalDecl)) { auto &fixedTI = IGM.getTypeInfo(loweredTy); if (isa(fixedTI)) return; - if (IGM.Context.LangOpts.hasFeature(Feature::LayoutStringValueWitnesses) && - IGM.Context.LangOpts.hasFeature( - Feature::LayoutStringValueWitnessesInstantiation) && - IGM.getOptions().EnableLayoutStringValueWitnesses && - IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation) { + if (useLayoutStrings) { emitInitializeFieldOffsetVectorWithLayoutString(IGF, loweredTy, metadata, isVWTMutable, collector); } else { @@ -3021,9 +3022,16 @@ static void emitInitializeValueMetadata(IRGenFunction &IGF, } } else { assert(isa(nominalDecl)); + auto &strategy = getEnumImplStrategy(IGM, loweredTy); - strategy.initializeMetadata(IGF, metadata, isVWTMutable, loweredTy, - collector); + + if (useLayoutStrings) { + strategy.initializeMetadataWithLayoutString(IGF, metadata, isVWTMutable, + loweredTy, collector); + } else { + strategy.initializeMetadata(IGF, metadata, isVWTMutable, loweredTy, + collector); + } } } @@ -5721,10 +5729,28 @@ namespace { return {global, offset, structSize}; } + bool hasLayoutString() { + if (!IGM.Context.LangOpts.hasFeature( + Feature::LayoutStringValueWitnesses) || + !IGM.getOptions().EnableLayoutStringValueWitnesses) { + return false; + } + + auto &strategy = getEnumImplStrategy(IGM, getLoweredType()); + + return !!getLayoutString() || + (IGM.Context.LangOpts.hasFeature( + Feature::LayoutStringValueWitnessesInstantiation) && + IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation && + (HasDependentVWT || HasDependentMetadata) && + !isa(IGM.getTypeInfo(getLoweredType())) && + strategy.getElementsWithPayload().size() > 1); + } + llvm::Constant *emitNominalTypeDescriptor() { return EnumContextDescriptorBuilder( IGM, Target, RequireMetadata, - /*hasLayoutString*/ !!getLayoutString()) + /*hasLayoutString*/ hasLayoutString()) .emit(); } @@ -5746,7 +5772,7 @@ namespace { bool hasCompletionFunction() { return !isa(IGM.getTypeInfo(getLoweredType())) || - !!getLayoutString(); + hasLayoutString(); } }; diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp index 8768ba476c48d..886297dd948a3 100644 --- a/lib/IRGen/GenValueWitness.cpp +++ b/lib/IRGen/GenValueWitness.cpp @@ -891,6 +891,9 @@ bool isRuntimeInstatiatedLayoutString(IRGenModule &IGM, IGM.Context.LangOpts.hasFeature( Feature::LayoutStringValueWitnessesInstantiation) && IGM.getOptions().EnableLayoutStringValueWitnessesInstantiation) { + if (auto *enumEntry = typeLayoutEntry->getAsEnum()) { + return enumEntry->isMultiPayloadEnum(); + } return (typeLayoutEntry->isAlignedGroup() && !typeLayoutEntry->isFixedSize(IGM)); } diff --git a/lib/IRGen/TypeLayout.cpp b/lib/IRGen/TypeLayout.cpp index c89ea702061fe..5ef1e9fbd1f60 100644 --- a/lib/IRGen/TypeLayout.cpp +++ b/lib/IRGen/TypeLayout.cpp @@ -83,6 +83,7 @@ class LayoutStringBuilder { MultiPayloadEnumFN = 0x13, // reserved // MultiPayloadEnumFNResolved = 0x14, + // MultiPayloadEnumGeneric = 0x15, Skip = 0x80, // We may use the MSB as flag that a count follows, diff --git a/stdlib/public/runtime/BytecodeLayouts.cpp b/stdlib/public/runtime/BytecodeLayouts.cpp index 5e45145f10d0a..64550ce438d41 100644 --- a/stdlib/public/runtime/BytecodeLayouts.cpp +++ b/stdlib/public/runtime/BytecodeLayouts.cpp @@ -126,6 +126,11 @@ inline static bool handleNextRefCount(const Metadata *metadata, Handler::handleMultiPayloadEnumFN(metadata, typeLayout, offset, true, addrOffset, std::forward(params)...); + } else if (SWIFT_UNLIKELY(tag == + RefCountingKind::MultiPayloadEnumGeneric)) { + Handler::handleMultiPayloadEnumGeneric(metadata, typeLayout, offset, + addrOffset, + std::forward(params)...); } else { Handler::handleReference(tag, addrOffset, std::forward(params)...); } @@ -263,16 +268,46 @@ static void handleMultiPayloadEnumFN(const Metadata *metadata, getEnumTag = readRelativeFunctionPointer(typeLayout, offset); } - size_t numCases = readBytes(typeLayout, offset); + size_t numPayloads = readBytes(typeLayout, offset); size_t refCountBytes = readBytes(typeLayout, offset); size_t enumSize = readBytes(typeLayout, offset); unsigned enumTag = getEnumTag(addr + addrOffset); - if (enumTag < numCases) { + if (enumTag < numPayloads) { + size_t nestedOffset = offset + (enumTag * sizeof(size_t)); + size_t refCountOffset = readBytes(typeLayout, nestedOffset); + nestedOffset = offset + (numPayloads * sizeof(size_t)) + refCountOffset; + + uintptr_t nestedAddrOffset = addrOffset; + handleRefCounts<0, Handler>(metadata, typeLayout, nestedOffset, + nestedAddrOffset, addr, + std::forward(params)...); + } + + offset += refCountBytes + (numPayloads * sizeof(size_t)); + addrOffset += enumSize; +} + +template +static void handleMultiPayloadEnumGeneric(const Metadata *metadata, + const uint8_t *typeLayout, + size_t &offset, + uintptr_t &addrOffset, + uint8_t *addr, + Params... params) { + auto tagBytes = readBytes(typeLayout, offset); + auto numPayloads = readBytes(typeLayout, offset); + auto refCountBytes = readBytes(typeLayout, offset); + auto enumSize = readBytes(typeLayout, offset); + auto tagBytesOffset = enumSize - tagBytes; + + auto enumTag = readTagBytes(addr + addrOffset + tagBytesOffset, tagBytes); + + if (enumTag < numPayloads) { size_t nestedOffset = offset + (enumTag * sizeof(size_t)); size_t refCountOffset = readBytes(typeLayout, nestedOffset); - nestedOffset = offset + (numCases * sizeof(size_t)) + refCountOffset; + nestedOffset = offset + (numPayloads * sizeof(size_t)) + refCountOffset; uintptr_t nestedAddrOffset = addrOffset; handleRefCounts<0, Handler>(metadata, typeLayout, nestedOffset, @@ -280,7 +315,7 @@ static void handleMultiPayloadEnumFN(const Metadata *metadata, std::forward(params)...); } - offset += refCountBytes + (numCases * sizeof(size_t)); + offset += refCountBytes + (numPayloads * sizeof(size_t)); addrOffset += enumSize; } @@ -337,6 +372,15 @@ struct DestroyHandler { resolved, addrOffset, addr); } + static inline void handleMultiPayloadEnumGeneric(const Metadata *metadata, + const uint8_t *typeLayout, + size_t &offset, + uintptr_t &addrOffset, + uint8_t *addr) { + ::handleMultiPayloadEnumGeneric(metadata, typeLayout, offset, + addrOffset, addr); + } + static inline void handleReference(RefCountingKind tag, uintptr_t addrOffset, uint8_t *addr) { const auto &destroyFunc = destroyTable[static_cast(tag)]; @@ -431,6 +475,16 @@ struct CopyHandler { resolved, addrOffset, dest, src); } + static inline void handleMultiPayloadEnumGeneric(const Metadata *metadata, + const uint8_t *typeLayout, + size_t &offset, + uintptr_t &addrOffset, + uint8_t *dest, + uint8_t *src) { + ::handleMultiPayloadEnumGeneric(metadata, typeLayout, offset, + addrOffset, dest, src); + } + static inline void handleReference(RefCountingKind tag, uintptr_t addrOffset, uint8_t *dest, uint8_t *src) { const auto &retainFunc = retainTable[static_cast(tag)]; @@ -488,6 +542,16 @@ struct TakeHandler { resolved, addrOffset, dest, src); } + static inline void handleMultiPayloadEnumGeneric(const Metadata *metadata, + const uint8_t *typeLayout, + size_t &offset, + uintptr_t &addrOffset, + uint8_t *dest, + uint8_t *src) { + ::handleMultiPayloadEnumGeneric(metadata, typeLayout, offset, + addrOffset, dest, src); + } + static inline void handleReference(RefCountingKind tag, uintptr_t addrOffset, uint8_t *dest, uint8_t *src) { if (tag == RefCountingKind::UnknownWeak) { diff --git a/stdlib/public/runtime/BytecodeLayouts.h b/stdlib/public/runtime/BytecodeLayouts.h index f5e487428927b..2a4fafd742fcc 100644 --- a/stdlib/public/runtime/BytecodeLayouts.h +++ b/stdlib/public/runtime/BytecodeLayouts.h @@ -49,6 +49,7 @@ enum class RefCountingKind : uint8_t { MultiPayloadEnumFN = 0x13, MultiPayloadEnumFNResolved = 0x14, + MultiPayloadEnumGeneric = 0x15, Skip = 0x80, // We may use the MSB as flag that a count follows, diff --git a/stdlib/public/runtime/Enum.cpp b/stdlib/public/runtime/Enum.cpp index f1fdddd3a386e..13c00ed9dcc97 100644 --- a/stdlib/public/runtime/Enum.cpp +++ b/stdlib/public/runtime/Enum.cpp @@ -18,7 +18,9 @@ #include "swift/Runtime/Enum.h" #include "swift/Runtime/Debug.h" #include "Private.h" +#include "BytecodeLayouts.h" #include "EnumImpl.h" +#include "MetadataCache.h" #include #include @@ -214,65 +216,143 @@ swift::swift_initEnumMetadataMultiPayload(EnumMetadata *enumType, vwtable->publishLayout(layout); } -// void -// swift::swift_initEnumMetadataMultiPayloadWithLayoutString(EnumMetadata *enumType, -// EnumLayoutFlags layoutFlags, -// unsigned numPayloads, -// const TypeLayout * const *payloadLayouts) { - // // Accumulate the layout requirements of the payloads. - // size_t payloadSize = 0, alignMask = 0; - // bool isPOD = true, isBT = true; - // for (unsigned i = 0; i < numPayloads; ++i) { - // const TypeLayout *payloadLayout = payloadLayouts[i]; - // payloadSize - // = std::max(payloadSize, (size_t)payloadLayout->size); - // alignMask |= payloadLayout->flags.getAlignmentMask(); - // isPOD &= payloadLayout->flags.isPOD(); - // isBT &= payloadLayout->flags.isBitwiseTakable(); - // } - - // // Store the max payload size in the metadata. - // assignUnlessEqual(enumType->getPayloadSize(), payloadSize); - - // // The total size includes space for the tag. - // auto tagCounts = getEnumTagCounts(payloadSize, - // enumType->getDescription()->getNumEmptyCases(), - // numPayloads); - // unsigned totalSize = payloadSize + tagCounts.numTagBytes; - - // // See whether there are extra inhabitants in the tag. - // unsigned numExtraInhabitants = tagCounts.numTagBytes == 4 - // ? INT_MAX - // : (1 << (tagCounts.numTagBytes * 8)) - tagCounts.numTags; - // numExtraInhabitants = std::min(numExtraInhabitants, - // unsigned(ValueWitnessFlags::MaxNumExtraInhabitants)); - - // auto vwtable = getMutableVWTableForInit(enumType, layoutFlags); - - // // Set up the layout info in the vwtable. - // auto rawStride = (totalSize + alignMask) & ~alignMask; - // TypeLayout layout{totalSize, - // rawStride == 0 ? 1 : rawStride, - // ValueWitnessFlags() - // .withAlignmentMask(alignMask) - // .withPOD(isPOD) - // .withBitwiseTakable(isBT) - // .withEnumWitnesses(true) - // .withInlineStorage(ValueWitnessTable::isValueInline( - // isBT, totalSize, alignMask + 1)), - // numExtraInhabitants}; - - // installCommonValueWitnesses(layout, vwtable); - - // // Unconditionally overwrite the enum-tag witnesses. - // // The compiler does not generate meaningful enum-tag witnesses for - // // enums in this state. - // vwtable->getEnumTagSinglePayload = swift_getMultiPayloadEnumTagSinglePayload; - // vwtable->storeEnumTagSinglePayload = - // swift_storeMultiPayloadEnumTagSinglePayload; - - // vwtable->publishLayout(layout); -//} +void swift::swift_initEnumMetadataMultiPayloadWithLayoutString( + EnumMetadata *enumType, + EnumLayoutFlags layoutFlags, + unsigned numPayloads, + const Metadata * const *payloadLayouts) { + // Accumulate the layout requirements of the payloads. + size_t payloadSize = 0, alignMask = 0; + bool isPOD = true, isBT = true; + + size_t payloadRefCountBytes = 0; + for (unsigned i = 0; i < numPayloads; ++i) { + const TypeLayout *payloadLayout = payloadLayouts[i]->getTypeLayout(); + payloadSize + = std::max(payloadSize, (size_t)payloadLayout->size); + alignMask |= payloadLayout->flags.getAlignmentMask(); + isPOD &= payloadLayout->flags.isPOD(); + isBT &= payloadLayout->flags.isBitwiseTakable(); + + payloadRefCountBytes += _swift_refCountBytesForMetatype(payloadLayouts[i]); + // NUL terminator + payloadRefCountBytes += sizeof(uint64_t); + } + + // Store the max payload size in the metadata. + assignUnlessEqual(enumType->getPayloadSize(), payloadSize); + + // The total size includes space for the tag. + auto tagCounts = getEnumTagCounts(payloadSize, + enumType->getDescription()->getNumEmptyCases(), + numPayloads); + unsigned totalSize = payloadSize + tagCounts.numTagBytes; + + // See whether there are extra inhabitants in the tag. + unsigned numExtraInhabitants = tagCounts.numTagBytes == 4 + ? INT_MAX + : (1 << (tagCounts.numTagBytes * 8)) - tagCounts.numTags; + numExtraInhabitants = std::min(numExtraInhabitants, + unsigned(ValueWitnessFlags::MaxNumExtraInhabitants)); + + auto vwtable = getMutableVWTableForInit(enumType, layoutFlags); + + // Instantiate layout string + { + const size_t fixedLayoutHeaderSize = layoutStringHeaderSize + + sizeof(uint64_t) + // Tag + offset + sizeof(size_t) + // Extra tag byte count + sizeof(size_t) * 3; // Payload count, ref count bytes, enum size + + const size_t allocationSize = fixedLayoutHeaderSize + + (numPayloads * sizeof(size_t)) + // Payload ref count offsets + payloadRefCountBytes + + sizeof(uint64_t) * 2; // Last skip bytes + NUL terminator + + uint8_t *layoutStr = (uint8_t *)MetadataAllocator(LayoutStringTag) + .Allocate(allocationSize, alignof(uint8_t)); + + size_t layoutStrOffset = sizeof(uint64_t); + uint64_t tagAndOffset = ((uint64_t)RefCountingKind::MultiPayloadEnumGeneric) << 56; + + size_t refCountBytes = allocationSize - layoutStringHeaderSize - + (sizeof(uint64_t) * 2); + writeBytes(layoutStr, layoutStrOffset, refCountBytes); + writeBytes(layoutStr, layoutStrOffset, tagAndOffset); + writeBytes(layoutStr, layoutStrOffset, size_t(tagCounts.numTagBytes)); + writeBytes(layoutStr, layoutStrOffset, size_t(numPayloads)); + writeBytes(layoutStr, layoutStrOffset, payloadRefCountBytes); + writeBytes(layoutStr, layoutStrOffset, size_t(totalSize)); + + size_t fullOffset = 0; + LayoutStringFlags flags = LayoutStringFlags::Empty; + + size_t payloadRefCountOffsetOffset = layoutStrOffset; + size_t payloadRefCountOffset = 0; + + layoutStrOffset += sizeof(size_t) * numPayloads; + + for (unsigned i = 0; i < numPayloads; ++i) { + const Metadata *payloadType = payloadLayouts[i]; + + writeBytes(layoutStr, payloadRefCountOffsetOffset, payloadRefCountOffset); + + size_t layoutStrOffsetBefore = layoutStrOffset; + size_t previousFieldOffset = 0; + _swift_addRefCountStringForMetatype(layoutStr, layoutStrOffset, flags, + payloadType, fullOffset, + previousFieldOffset); + + // NUL terminator + writeBytes(layoutStr, layoutStrOffset, 0); + + payloadRefCountOffset += (layoutStrOffset - layoutStrOffsetBefore); + } + + // Last skip bytes (always 0 for enums) + writeBytes(layoutStr, layoutStrOffset, 0); + // NUL terminator + writeBytes(layoutStr, layoutStrOffset, 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)); + + enumType->setLayoutString(layoutStr); + + 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; + } + + // Set up the layout info in the vwtable. + auto rawStride = (totalSize + alignMask) & ~alignMask; + TypeLayout layout{totalSize, + rawStride == 0 ? 1 : rawStride, + ValueWitnessFlags() + .withAlignmentMask(alignMask) + .withPOD(isPOD) + .withBitwiseTakable(isBT) + .withEnumWitnesses(true) + .withInlineStorage(ValueWitnessTable::isValueInline( + isBT, totalSize, alignMask + 1)), + numExtraInhabitants}; + + installCommonValueWitnesses(layout, vwtable); + + // Unconditionally overwrite the enum-tag witnesses. + // The compiler does not generate meaningful enum-tag witnesses for + // enums in this state. + vwtable->getEnumTagSinglePayload = swift_getMultiPayloadEnumTagSinglePayload; + vwtable->storeEnumTagSinglePayload = + swift_storeMultiPayloadEnumTagSinglePayload; + + vwtable->publishLayout(layout); +} namespace { struct MultiPayloadLayout { diff --git a/test/Interpreter/layout_string_witnesses_dynamic.swift b/test/Interpreter/layout_string_witnesses_dynamic.swift index 4d1d441c9545a..cf402abf8ef8c 100644 --- a/test/Interpreter/layout_string_witnesses_dynamic.swift +++ b/test/Interpreter/layout_string_witnesses_dynamic.swift @@ -306,7 +306,7 @@ enum TestEnum { func testGenericWithEnumNonEmpty() { let ptr = allocateInternalGenericPtr(of: TestEnum.self) - + do { let x = TestClass() testGenericInit(ptr, to: TestEnum.nonEmpty(x)) @@ -336,7 +336,7 @@ public struct ResilientWrapper { func testResilient() { let ptr = UnsafeMutablePointer.allocate(capacity: 1) - + do { let x = TestClass() testInit(ptr, to: ResilientWrapper(x: SimpleResilient(x: 23, y: x), y: 5)) @@ -369,7 +369,7 @@ public struct GenericResilientWrapper { func testGenericResilient() { let ptr = UnsafeMutablePointer>.allocate(capacity: 1) - + do { let x = TestClass() testInit(ptr, to: GenericResilientWrapper(x: GenericResilient(x: x, y: 32), y: 32))