Skip to content

[Remote Mirror] Pass spare bit data for multi-payload enums from compiler #34990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 62 additions & 4 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -1562,7 +1562,7 @@ struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
using StoredSize = typename Runtime::StoredSize;
using TargetValueMetadata<Runtime>::TargetValueMetadata;

const TargetEnumDescriptor<Runtime> *getDescription() const {
const swift::TargetEnumDescriptor<Runtime> *getDescription() const {
return llvm::cast<TargetEnumDescriptor<Runtime>>(this->Description);
}

Expand Down Expand Up @@ -1617,6 +1617,14 @@ struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
return trailingFlags->isCanonicalStaticSpecialization();
}

bool hasSpareBits() const {
return getDescription()->hasSpareBits();
}

size_t getEnumSpareBits() const {
return getDescription()->getEnumSpareBits();
}

const MetadataTrailingFlags *getTrailingFlags() const {
auto description = getDescription();
auto flags = description->getFullGenericContextHeader()
Expand Down Expand Up @@ -3048,6 +3056,7 @@ class TrailingGenericContextObjects<TargetSelf<Runtime>,
public:
using StoredSize = typename Runtime::StoredSize;
using StoredPointer = typename Runtime::StoredPointer;
using TrailingObjects::totalSizeOfPartialObject;

const GenericContextHeaderType &getFullGenericContextHeader() const {
assert(asSelf()->isGeneric());
Expand Down Expand Up @@ -3225,7 +3234,7 @@ struct TargetAnonymousContextDescriptor final
using TrailingGenericContextObjects::numTrailingObjects;

size_t numTrailingObjects(OverloadToken<MangledContextName>) const {
return this->hasMangledNam() ? 1 : 0;
return this->hasMangledName() ? 1 : 0;
}

public:
Expand Down Expand Up @@ -4645,6 +4654,16 @@ class TargetStructDescriptor final

using StructDescriptor = TargetStructDescriptor<InProcess>;

// Enum spare bits mask is stored as 1 "header" followed by some number of "chunks" that hold the actual mask bits.
template <typename Runtime>
struct TargetEnumSpareBitsHeader {
uint32_t bytesCount;
};
template <typename Runtime>
struct TargetEnumSpareBitsChunk {
uint32_t value;
};

template <typename Runtime>
class TargetEnumDescriptor final
: public TargetValueTypeDescriptor<Runtime>,
Expand All @@ -4655,7 +4674,9 @@ class TargetEnumDescriptor final
TargetSingletonMetadataInitialization<Runtime>,
TargetCanonicalSpecializedMetadatasListCount<Runtime>,
TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>,
TargetEnumSpareBitsHeader<Runtime>,
TargetEnumSpareBitsChunk<Runtime>> {
public:
using SingletonMetadataInitialization =
TargetSingletonMetadataInitialization<Runtime>;
Expand All @@ -4669,6 +4690,10 @@ class TargetEnumDescriptor final
TargetCanonicalSpecializedMetadatasListEntry<Runtime>;
using MetadataCachingOnceToken =
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>;
using EnumSpareBitsHeader =
TargetEnumSpareBitsHeader<Runtime>;
using EnumSpareBitsChunk =
TargetEnumSpareBitsChunk<Runtime>;

private:
using TrailingGenericContextObjects =
Expand All @@ -4678,7 +4703,9 @@ class TargetEnumDescriptor final
SingletonMetadataInitialization,
MetadataListCount,
MetadataListEntry,
MetadataCachingOnceToken>;
MetadataCachingOnceToken,
EnumSpareBitsHeader,
EnumSpareBitsChunk>;

using TrailingObjects =
typename TrailingGenericContextObjects::TrailingObjects;
Expand Down Expand Up @@ -4712,6 +4739,21 @@ class TargetEnumDescriptor final
return this->hasCanonicicalMetadataPrespecializations() ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<EnumSpareBitsHeader>) const {
return hasSpareBits() ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<EnumSpareBitsChunk>) const {
if (hasSpareBits()) {
auto value = this->template getTrailingObjects<EnumSpareBitsHeader>();
auto bytes = value->bytesCount;
auto chunkSize = sizeof(EnumSpareBitsChunk);
return (bytes + chunkSize - 1) / chunkSize;
} else {
return 0;
}
}

public:
using TrailingGenericContextObjects::getGenericContext;
using TrailingGenericContextObjects::getGenericContextHeader;
Expand Down Expand Up @@ -4744,6 +4786,10 @@ class TargetEnumDescriptor final
return getPayloadSizeOffset() != 0;
}

bool hasSpareBits() const {
return this->getTypeContextDescriptorFlags().enum_hasSpareBits();
}

static constexpr int32_t getGenericArgumentOffset() {
return TargetEnumMetadata<Runtime>::getGenericArgumentOffset();
}
Expand Down Expand Up @@ -4779,6 +4825,18 @@ class TargetEnumDescriptor final
return box->token.get();
}

// TODO: Fix up return type...
size_t getEnumSpareBits() const {
assert(hasSpareBits());
auto header = *this->template getTrailingObjects<EnumSpareBitsHeader>();
size_t length = header.bytesCount;
// EnumSpareBitsChunk *chunks = this->template getTrailingObjects<EnumSpareBitsChunk>();
auto chunks = this->template getTrailingObjects<EnumSpareBitsChunk>();
// TODO: Convert mask data into some sort of SpareBits object

return length;
}

static bool classof(const TargetContextDescriptor<Runtime> *cd) {
return cd->getKind() == ContextDescriptorKind::Enum;
}
Expand Down
14 changes: 14 additions & 0 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,13 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
///
/// Only meaningful for class descriptors.
Class_HasVTable = 15,

/// Set if the context descriptor includes a spare bit mask
Enum_HasSpareBits = 9,

/// Set if this is a "simple" Multi-payload enum that uses
/// a trailing tag to discriminate cases (no XIs or spare bits)
Enum_SimpleMPE = 10
};

public:
Expand Down Expand Up @@ -1522,6 +1529,13 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
TypeReferenceKind,
class_getResilientSuperclassReferenceKind,
class_setResilientSuperclassReferenceKind)

FLAGSET_DEFINE_FLAG_ACCESSORS(Enum_HasSpareBits,
enum_hasSpareBits,
enum_setHasSpareBits)
FLAGSET_DEFINE_FLAG_ACCESSORS(Enum_SimpleMPE,
enum_simpleMPE,
enum_setSimpleMPE)
};

/// Extra flags for resilient classes, since we need more than 16 bits of
Expand Down
75 changes: 73 additions & 2 deletions include/swift/ABI/TrailingObjects.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,30 @@ class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
return reinterpret_cast<NextTy *>(Ptr);
}

using ParentType::estimatedSizeOfPartialTrailingObjects;

static size_t
estimatedSizeOfPartialTrailingObjects(size_t available,
BaseTy *Obj,
TrailingObjectsBase::OverloadToken<NextTy>) {
size_t previousSize = TopTrailingObj::estimatedSizeOfPartialTrailingObjects(
available, Obj, TrailingObjectsBase::OverloadToken<PrevTy>());
if (requiresRealignment()) {
// Pretend `previousSize` is a pointer to a trailing object of a
// descriptor based at address zero so we can just use the
// standard alignment calculations.
previousSize = llvm::alignAddr((const void *)previousSize,
llvm::Align(alignof(NextTy)));
}
if (previousSize <= available) {
auto count = TopTrailingObj::callNumTrailingObjects(
Obj, TrailingObjectsBase::OverloadToken<NextTy>());
previousSize += sizeof(NextTy) * count;
}
return previousSize;
}

protected:
// Helper function for TrailingObjects::additionalSizeToAlloc: this
// function recurses to superclasses, each of which requires one
// fewer size_t argument, and adds its own size.
Expand Down Expand Up @@ -224,6 +248,13 @@ class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
return SizeSoFar;
}

static size_t
estimatedSizeOfPartialTrailingObjects(size_t available,
BaseTy *Obj) {
return TopTrailingObj::estimatedSizeOfPartialTrailingObjects(
available, Obj, TrailingObjectsBase::OverloadToken<PrevTy>());
}

template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {}
};

Expand Down Expand Up @@ -292,8 +323,8 @@ class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl<
#else
// MSVC bug prevents the above from working, at least up through CL
// 19.10.24629.
template <typename T>
using OverloadToken = typename ParentType::template OverloadToken<T>;
template <typename... T>
using OverloadToken = typename ParentType::template OverloadToken<T...>;
#endif

/// Returns a pointer to the trailing object array of the given type
Expand All @@ -317,6 +348,46 @@ class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl<
static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>());
}

/// `totalSizeOfPartialObject` returns the total size of the object to the
/// extent that it can be determined based on the partial object currently
/// available.
///
/// This is useful when copying objects from another address space; you can't
/// easily query the size of the remote object directly, so instead copy
/// enough data to get the base class, then use this to determine if you need
/// to copy more. There are two cases:
///
/// 1. The partial data contains the full object. In this case, the
/// returned size will be less than or equal to the provided size.
///
/// 2. The partial data is not a complete object. In this case, the returned
/// size will be an estimate that is larger than the provided size.
/// Note that the returned size may be smaller or larger than the true size of the
/// object.
///
/// In short, if the return value is larger than the provided size, you should
/// fetch more and try again. Note that if the returned size is larger than
/// the provided size, all you really know is that the current data is
/// insufficient. In particular, you cannot avoid calling this method again
/// after you fetch more data.

// Recursively defined helpers...
using ParentType::estimatedSizeOfPartialTrailingObjects;

// Base case that just returns size of the base type.
static size_t
estimatedSizeOfPartialTrailingObjects(size_t available,
BaseTy *Obj,
TrailingObjectsBase::OverloadToken<BaseTy>) {
return sizeof(BaseTy);
}

static size_t
totalSizeOfPartialObject(uint8_t *buffer, size_t available) {
return ParentType::estimatedSizeOfPartialTrailingObjects(
available, reinterpret_cast<BaseTy *>(buffer));
}

/// Returns the size of the trailing data, if an object were
/// allocated with the given counts (The counts are in the same order
/// as the template arguments). This does not include the size of the
Expand Down
Loading