Skip to content

Update the metadata-initialization ABI #13570

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

Merged
merged 1 commit into from
Dec 21, 2017
Merged
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
5 changes: 3 additions & 2 deletions docs/Runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,9 @@ runtime.
000000000001e620 T _swift_allocateGenericValueMetadata
0000000000022be0 T _swift_initClassMetadata_UniversalStrategy
000000000001c100 T _swift_initEnumMetadataMultiPayload
000000000001bd60 T _swift_initEnumValueWitnessTableSinglePayload
0000000000022a20 T _swift_initStructMetadata_UniversalStrategy
000000000001bd60 T _swift_initEnumMetadataSingleCase
000000000001bd60 T _swift_initEnumMetadataSinglePayload
0000000000022a20 T _swift_initStructMetadata
0000000000024230 T _swift_initializeSuperclass
0000000000028b60 T _swift_instantiateObjCClass
```
Expand Down
56 changes: 56 additions & 0 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,62 @@ static inline bool isWarningOnly(ExclusivityFlags flags) {
return uintptr_t(flags) & uintptr_t(ExclusivityFlags::WarningOnly);
}

/// Flags for struct layout.
enum class StructLayoutFlags : uintptr_t {
/// Reserve space for 256 layout algorithms.
AlgorithmMask = 0xff,

/// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
Swift5Algorithm = 0x00,

/// Is the value-witness table mutable in place, or does layout need to
/// clone it?
IsVWTMutable = 0x100,
};
static inline StructLayoutFlags operator|(StructLayoutFlags lhs,
StructLayoutFlags rhs) {
return StructLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
}
static inline StructLayoutFlags &operator|=(StructLayoutFlags &lhs,
StructLayoutFlags rhs) {
return (lhs = (lhs | rhs));
}
static inline StructLayoutFlags getLayoutAlgorithm(StructLayoutFlags flags) {
return StructLayoutFlags(uintptr_t(flags)
& uintptr_t(StructLayoutFlags::AlgorithmMask));
}
static inline bool isValueWitnessTableMutable(StructLayoutFlags flags) {
return uintptr_t(flags) & uintptr_t(StructLayoutFlags::IsVWTMutable);
}

/// Flags for enum layout.
enum class EnumLayoutFlags : uintptr_t {
/// Reserve space for 256 layout algorithms.
AlgorithmMask = 0xff,

/// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
Swift5Algorithm = 0x00,

/// Is the value-witness table mutable in place, or does layout need to
/// clone it?
IsVWTMutable = 0x100,
};
static inline EnumLayoutFlags operator|(EnumLayoutFlags lhs,
EnumLayoutFlags rhs) {
return EnumLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
}
static inline EnumLayoutFlags &operator|=(EnumLayoutFlags &lhs,
EnumLayoutFlags rhs) {
return (lhs = (lhs | rhs));
}
static inline EnumLayoutFlags getLayoutAlgorithm(EnumLayoutFlags flags) {
return EnumLayoutFlags(uintptr_t(flags)
& uintptr_t(EnumLayoutFlags::AlgorithmMask));
}
static inline bool isValueWitnessTableMutable(EnumLayoutFlags flags) {
return uintptr_t(flags) & uintptr_t(EnumLayoutFlags::IsVWTMutable);
}

} // end namespace swift

#endif /* SWIFT_ABI_METADATAVALUES_H */
32 changes: 22 additions & 10 deletions include/swift/Runtime/Enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,29 @@ template <typename Runtime> struct TargetEnumMetadata;
using EnumMetadata = TargetEnumMetadata<InProcess>;
struct TypeLayout;

/// \brief Initialize the value witness table for a generic, single-payload
/// enum instance.
/// \brief Initialize the type metadata for a single-case enum type.
///
/// \param enumType - pointer to the instantiated but uninitialized metadata
/// for the enum.
/// \param flags - flags controlling the layout
/// \param payload - type metadata for the payload of the enum.
SWIFT_RUNTIME_EXPORT
void swift_initEnumMetadataSingleCase(EnumMetadata *enumType,
EnumLayoutFlags flags,
const TypeLayout *payload);

/// \brief Initialize the type metadata for a single-payload enum type.
///
/// \param vwtable - pointer to the instantiated but uninitialized value
/// witness table for the enum.
/// \param enumType - pointer to the instantiated but uninitialized metadata
/// for the enum.
/// \param flags - flags controlling the layout
/// \param payload - type metadata for the payload case of the enum.
/// \param emptyCases - the number of empty cases in the enum.
SWIFT_RUNTIME_EXPORT
void swift_initEnumValueWitnessTableSinglePayload(ValueWitnessTable *vwtable,
const TypeLayout *payload,
unsigned emptyCases);
void swift_initEnumMetadataSinglePayload(EnumMetadata *enumType,
EnumLayoutFlags flags,
const TypeLayout *payload,
unsigned emptyCases);

/// \brief Faster variant of the above which avoids digging into the enum type
/// metadata when the caller already has the payload information handy.
Expand Down Expand Up @@ -81,11 +93,11 @@ void swift_storeEnumTagSinglePayload(OpaqueValue *value,
unsigned emptyCases)
SWIFT_CC(RegisterPreservingCC);

/// \brief Initialize the value witness table for a generic, multi-payload
/// \brief Initialize the type metadata for a generic, multi-payload
/// enum instance.
SWIFT_RUNTIME_EXPORT
void swift_initEnumMetadataMultiPayload(ValueWitnessTable *vwtable,
EnumMetadata *enumType,
void swift_initEnumMetadataMultiPayload(EnumMetadata *enumType,
EnumLayoutFlags flags,
unsigned numPayloads,
const TypeLayout * const *payloadTypes);

Expand Down
9 changes: 5 additions & 4 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -2901,10 +2901,11 @@ swift_getTupleTypeMetadata3(const Metadata *elt0, const Metadata *elt1,
/// Initialize the value witness table and struct field offset vector for a
/// struct, using the "Universal" layout strategy.
SWIFT_RUNTIME_EXPORT
void swift_initStructMetadata_UniversalStrategy(size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets,
ValueWitnessTable *vwtable);
void swift_initStructMetadata(StructMetadata *self,
StructLayoutFlags flags,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets);

/// Relocate the metadata for a class and copy fields from the given template.
/// The final size of the metadata is calculated at runtime from the size of
Expand Down
52 changes: 31 additions & 21 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -968,37 +968,47 @@ FUNCTION(InitClassMetadataUniversal,
SizeTy->getPointerTo()),
ATTRS(NoUnwind))

// void swift_initStructMetadata_UniversalStrategy(size_t numFields,
// TypeLayout * const *fieldTypes,
// size_t *fieldOffsets,
// value_witness_table_t *vwtable);
FUNCTION(InitStructMetadataUniversal,
swift_initStructMetadata_UniversalStrategy, DefaultCC,
RETURNS(VoidTy),
ARGS(SizeTy, Int8PtrPtrTy->getPointerTo(),
SizeTy->getPointerTo(), WitnessTablePtrTy),
ATTRS(NoUnwind))

// void swift_initEnumValueWitnessTableSinglePayload(value_witness_table_t *vwt,
// TypeLayout *payload,
// unsigned num_empty_cases);
FUNCTION(InitEnumValueWitnessTableSinglePayload,
swift_initEnumValueWitnessTableSinglePayload,
// void swift_initStructMetadata(Metadata *structType,
// StructLayoutFlags flags,
// size_t numFields,
// TypeLayout * const *fieldTypes,
// size_t *fieldOffsets);
FUNCTION(InitStructMetadata,
swift_initStructMetadata, DefaultCC,
RETURNS(VoidTy),
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0),
SizeTy->getPointerTo()),
ATTRS(NoUnwind))

// void swift_initEnumMetadataSingleCase(Metadata *enumType,
// EnumLayoutFlags flags,
// TypeLayout *payload);
FUNCTION(InitEnumMetadataSingleCase,
swift_initEnumMetadataSingleCase,
DefaultCC,
RETURNS(VoidTy),
ARGS(TypeMetadataPtrTy, SizeTy, Int8PtrPtrTy),
ATTRS(NoUnwind))

// void swift_initEnumMetadataSinglePayload(Metadata *enumType,
// EnumLayoutFlags flags,
// TypeLayout *payload,
// unsigned num_empty_cases);
FUNCTION(InitEnumMetadataSinglePayload,
swift_initEnumMetadataSinglePayload,
DefaultCC,
RETURNS(VoidTy),
ARGS(WitnessTablePtrTy, Int8PtrPtrTy, Int32Ty),
ARGS(TypeMetadataPtrTy, SizeTy, Int8PtrPtrTy, Int32Ty),
ATTRS(NoUnwind))

// void swift_initEnumMetadataMultiPayload(value_witness_table_t *vwt,
// Metadata *enumType,
// void swift_initEnumMetadataMultiPayload(Metadata *enumType,
// size_t numPayloads,
// TypeLayout * const *payloadTypes);
FUNCTION(InitEnumMetadataMultiPayload,
swift_initEnumMetadataMultiPayload,
DefaultCC,
RETURNS(VoidTy),
ARGS(WitnessTablePtrTy, TypeMetadataPtrTy, SizeTy,
Int8PtrPtrTy->getPointerTo(0)),
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0)),
ATTRS(NoUnwind))

// int swift_getEnumCaseSinglePayload(opaque_t *obj, Metadata *payload,
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/FixedTypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ class FixedTypeInfo : public TypeInfo {
/// Fixed-size types never need dynamic value witness table instantiation.
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable,
bool isVWTMutable,
SILType T) const override {}

void collectArchetypeMetadata(
Expand Down
104 changes: 28 additions & 76 deletions lib/IRGen/GenEnum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@
using namespace swift;
using namespace irgen;

static llvm::Constant *emitEnumLayoutFlags(IRGenModule &IGM, bool isVWTMutable){
// For now, we always use the Swift 5 algorithm.
auto flags = EnumLayoutFlags::Swift5Algorithm;
if (isVWTMutable) flags |= EnumLayoutFlags::IsVWTMutable;

return IGM.getSize(Size(uintptr_t(flags)));
}

SpareBitVector getBitVectorFromAPInt(const APInt &bits, unsigned startBit = 0) {
if (startBit == 0) {
return SpareBitVector::fromAPInt(bits);
Expand Down Expand Up @@ -587,78 +595,21 @@ namespace {

void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable,
bool isVWTMutable,
SILType T) const override {
// Fixed-size enums don't need dynamic witness table initialization.
if (TIK >= Fixed) return;

assert(!ElementsWithPayload.empty() &&
assert(ElementsWithPayload.size() == 1 &&
"empty singleton enum should not be dynamic!");

// Get the value witness table for the element.
SILType eltTy = T.getEnumElementType(ElementsWithPayload[0].decl,
IGM.getSILModule());
llvm::Value *eltLayout = IGF.emitTypeLayoutRef(eltTy);

Address vwtAddr(vwtable, IGF.IGM.getPointerAlignment());
Address eltLayoutAddr(eltLayout, IGF.IGM.getPointerAlignment());

auto getWitnessDestAndSrc = [&](ValueWitness witness,
Address *dest,
Address *src) {
*dest = IGF.Builder.CreateConstArrayGEP(vwtAddr,
unsigned(witness), IGF.IGM.getPointerSize());
*src = IGF.Builder.CreateConstArrayGEP(eltLayoutAddr,
unsigned(witness) - unsigned(ValueWitness::First_TypeLayoutWitness),
IGF.IGM.getPointerSize());
};

auto copyWitnessFromElt = [&](ValueWitness witness) {
Address dest, src;
getWitnessDestAndSrc(witness, &dest, &src);
auto val = IGF.Builder.CreateLoad(src);
IGF.Builder.CreateStore(val, dest);
};

copyWitnessFromElt(ValueWitness::Size);
copyWitnessFromElt(ValueWitness::Stride);

// Copy flags over, adding HasEnumWitnesses flag
auto copyFlagsFromElt = [&](ValueWitness witness) -> llvm::Value* {
Address dest, src;
getWitnessDestAndSrc(witness, &dest, &src);
auto val = IGF.Builder.CreateLoad(src);
auto ewFlag = IGF.Builder.CreatePtrToInt(val, IGF.IGM.SizeTy);
auto ewMask
= IGF.IGM.getSize(Size(ValueWitnessFlags::HasEnumWitnesses));
ewFlag = IGF.Builder.CreateOr(ewFlag, ewMask);
auto flag = IGF.Builder.CreateIntToPtr(ewFlag,
dest.getType()->getElementType());
IGF.Builder.CreateStore(flag, dest);
return val;
};

auto flags = copyFlagsFromElt(ValueWitness::Flags);

// If the original type had extra inhabitants, carry over its
// extra inhabitant flags.
auto xiBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
auto noXIBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());

auto xiFlag = IGF.Builder.CreatePtrToInt(flags, IGF.IGM.SizeTy);
auto xiMask
= IGF.IGM.getSize(Size(ValueWitnessFlags::Enum_HasExtraInhabitants));
xiFlag = IGF.Builder.CreateAnd(xiFlag, xiMask);
auto xiBool = IGF.Builder.CreateICmpNE(xiFlag,
IGF.IGM.getSize(Size(0)));
IGF.Builder.CreateCondBr(xiBool, xiBB, noXIBB);

IGF.Builder.emitBlock(xiBB);
ConditionalDominanceScope condition(IGF);
copyWitnessFromElt(ValueWitness::ExtraInhabitantFlags);
IGF.Builder.CreateBr(noXIBB);

IGF.Builder.emitBlock(noXIBB);
auto payloadTy = T.getEnumElementType(ElementsWithPayload[0].decl,
IGM.getSILModule());
auto payloadLayout = IGF.emitTypeLayoutRef(payloadTy);
auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
IGF.Builder.CreateCall(
IGF.IGM.getInitEnumMetadataSingleCaseFn(),
{metadata, flags, payloadLayout});
}

bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
Expand Down Expand Up @@ -904,7 +855,7 @@ namespace {

void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable,
bool isVWTMutable,
SILType T) const override {
// No-payload enums are always fixed-size so never need dynamic value
// witness table initialization.
Expand Down Expand Up @@ -2846,7 +2797,7 @@ namespace {

void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable,
bool isVWTMutable,
SILType T) const override {
// Fixed-size enums don't need dynamic witness table initialization.
if (TIK >= Fixed) return;
Expand All @@ -2858,10 +2809,10 @@ namespace {
auto payloadLayout = IGF.emitTypeLayoutRef(payloadTy);
auto emptyCasesVal = llvm::ConstantInt::get(IGF.IGM.Int32Ty,
ElementsWithNoPayload.size());

auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
IGF.Builder.CreateCall(
IGF.IGM.getInitEnumValueWitnessTableSinglePayloadFn(),
{vwtable, payloadLayout, emptyCasesVal});
IGF.IGM.getInitEnumMetadataSinglePayloadFn(),
{metadata, flags, payloadLayout, emptyCasesVal});
}

/// \group Extra inhabitants
Expand Down Expand Up @@ -4744,7 +4695,7 @@ namespace {

void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable,
bool isVWTMutable,
SILType T) const override {
// Fixed-size enums don't need dynamic metadata initialization.
if (TIK >= Fixed) return;
Expand All @@ -4754,8 +4705,9 @@ namespace {
auto numPayloadsVal = llvm::ConstantInt::get(IGF.IGM.SizeTy,
ElementsWithPayload.size());

auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable);
IGF.Builder.CreateCall(IGF.IGM.getInitEnumMetadataMultiPayloadFn(),
{vwtable, metadata, numPayloadsVal,
{metadata, flags, numPayloadsVal,
payloadLayoutArray});
}

Expand Down Expand Up @@ -5139,7 +5091,7 @@ namespace {

void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable,
bool isVWTMutable,
SILType T) const override {
llvm_unreachable("resilient enums cannot be defined");
}
Expand Down Expand Up @@ -5392,9 +5344,9 @@ namespace {
}
void initializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable,
bool isVWTMutable,
SILType T) const override {
return Strategy.initializeMetadata(IGF, metadata, vwtable, T);
return Strategy.initializeMetadata(IGF, metadata, isVWTMutable, T);
}
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
return Strategy.mayHaveExtraInhabitants(IGM);
Expand Down
Loading