IRGen: Start support for embedded existentials

Allow storing struct, enum, and tuple types in an any.
This commit is contained in:
Arnold Schwaighofer
2025-10-24 08:13:49 -07:00
parent c337446464
commit 4285a2169d
14 changed files with 343 additions and 35 deletions

View File

@@ -89,11 +89,17 @@ enum class TypeMetadataAddress {
inline bool isEmbedded(CanType t) {
return t->getASTContext().LangOpts.hasFeature(Feature::Embedded);
}
inline bool isEmbeddedWithoutEmbeddedExitentials(CanType t) {
return t->getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
!t->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials);
}
// Metadata is not generated and not allowed to be referenced in Embedded Swift,
// expect for classes (both generic and non-generic), dynamic self, and
// class-bound existentials.
inline bool isMetadataAllowedInEmbedded(CanType t) {
bool embeddedExistentials =
t->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials);
if (isa<ClassType>(t) || isa<BoundGenericClassType>(t) ||
isa<DynamicSelfType>(t)) {
return true;
@@ -106,6 +112,9 @@ inline bool isMetadataAllowedInEmbedded(CanType t) {
if (archeTy->requiresClass())
return true;
}
if (embeddedExistentials)
return true;
return false;
}
@@ -1098,7 +1107,7 @@ public:
}
static LinkEntity forValueWitnessTable(CanType type) {
assert(!isEmbedded(type));
assert(!isEmbeddedWithoutEmbeddedExitentials(type));
LinkEntity entity;
entity.setForType(Kind::ValueWitnessTable, type);
return entity;

View File

@@ -77,6 +77,8 @@ public:
// The regular `layout` method can be used for layout tasks for which the
// actual superclass pointer is not relevant.
void layoutEmbedded(CanType classTy) {
if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials))
asImpl().addValueWitnessTable();
asImpl().noteAddressPoint();
asImpl().addEmbeddedSuperclass(classTy);
asImpl().addDestructorFunction();
@@ -89,6 +91,8 @@ public:
"Adjustment index must be synchronized with this layout");
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials))
asImpl().addValueWitnessTable();
asImpl().noteAddressPoint();
asImpl().addSuperclass();
asImpl().addDestructorFunction();

View File

@@ -43,6 +43,14 @@ protected:
: super(IGM), Target(target) {}
public:
void embeddedLayout() {
// The embedded layout consists of:
// + // -1 : vwt
// + // 0 : metadata flags
super::layout();
}
void layout() {
static_assert(MetadataAdjustmentIndex::ValueType == 2,
"Adjustment index must be synchronized with this layout");

View File

@@ -1361,7 +1361,9 @@ deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRec
void IRGenerator::emitLazyDefinitions() {
if (SIL.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
// In embedded Swift, the compiler cannot emit any metadata, etc.
assert(LazyTypeMetadata.empty());
// Other than to support existentials.
assert(LazyTypeMetadata.empty() ||
SIL.getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials));
assert(LazySpecializedTypeMetadataRecords.empty());
assert(LazyTypeContextDescriptors.empty());
assert(LazyOpaqueTypeDescriptors.empty());
@@ -1388,7 +1390,8 @@ void IRGenerator::emitLazyDefinitions() {
!LazyCanonicalSpecializedMetadataAccessors.empty() ||
!LazyMetadataAccessors.empty() ||
!LazyClassMetadata.empty() ||
!LazySpecializedClassMetadata.empty()
!LazySpecializedClassMetadata.empty() ||
!LazySpecializedValueMetadata.empty()
) {
// Emit any lazy type metadata we require.
while (!LazyTypeMetadata.empty()) {
@@ -1514,6 +1517,12 @@ void IRGenerator::emitLazyDefinitions() {
CurrentIGMPtr IGM = getGenModule(classType->getClassOrBoundGenericClass());
emitLazySpecializedClassMetadata(*IGM.get(), classType);
}
while(!LazySpecializedValueMetadata.empty()) {
CanType valueType = LazySpecializedValueMetadata.pop_back_val();
CurrentIGMPtr IGM = getGenModule(valueType->getNominalOrBoundGenericNominal());
emitLazySpecializedValueMetadata(*IGM.get(), valueType);
}
}
FinishedEmittingLazyDefinitions = true;
@@ -1580,6 +1589,14 @@ bool IRGenerator::hasLazyMetadata(TypeDecl *type) {
if (found != HasLazyMetadata.end())
return found->second;
if (SIL.getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials) &&
(isa<StructDecl>(type) || isa<EnumDecl>(type))) {
bool isGeneric = cast<NominalTypeDecl>(type)->isGenericContext();
HasLazyMetadata[type] = !isGeneric;
return !isGeneric;
}
auto canBeLazy = [&]() -> bool {
auto *dc = type->getDeclContext();
if (isa<ClangModuleUnit>(dc->getModuleScopeContext())) {
@@ -1628,11 +1645,17 @@ void IRGenerator::noteUseOfClassMetadata(CanType classType) {
}
void IRGenerator::noteUseOfSpecializedClassMetadata(CanType classType) {
if (LazilyEmittedSpecializedClassMetadata.insert(classType.getPointer()).second) {
if (LazilyEmittedSpecializedMetadata.insert(classType.getPointer()).second) {
LazySpecializedClassMetadata.push_back(classType);
}
}
void IRGenerator::noteUseOfSpecializedValueMetadata(CanType valueType) {
if (LazilyEmittedSpecializedMetadata.insert(valueType.getPointer()).second) {
LazySpecializedValueMetadata.push_back(valueType);
}
}
void IRGenerator::noteUseOfTypeGlobals(NominalTypeDecl *type,
bool isUseOfMetadata,
RequireMetadata_t requireMetadata) {
@@ -5295,9 +5318,12 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
: LinkEntity::forTypeMetadata(
concreteType, TypeMetadataAddress::FullMetadata));
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
if (Context.LangOpts.hasFeature(Feature::Embedded) ) {
entity = LinkEntity::forTypeMetadata(concreteType,
TypeMetadataAddress::AddressPoint);
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials))
entity = LinkEntity::forTypeMetadata(concreteType,
TypeMetadataAddress::FullMetadata);
}
auto DbgTy = DebugTypeInfo::getGlobalMetadata(MetatypeType::get(concreteType),
@@ -5320,7 +5346,8 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
LinkInfo link = LinkInfo::get(*this, entity, ForDefinition);
markGlobalAsUsedBasedOnLinkage(*this, link, var);
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
if (Context.LangOpts.hasFeature(Feature::Embedded) &&
!Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
return var;
}
@@ -5331,12 +5358,15 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
if (auto nominal = concreteType->getAnyNominal()) {
// Keep type metadata around for all types (except @_objcImplementation,
// since we're using ObjC metadata for that).
if (!isObjCImpl)
if (!isObjCImpl &&
!Context.LangOpts.hasFeature(Feature::EmbeddedExistentials))
addRuntimeResolvableType(nominal);
// Don't define the alias for foreign type metadata, prespecialized
// generic metadata, or @_objcImplementation classes, since they're not ABI.
if (requiresForeignTypeMetadata(nominal) || isPrespecialized || isObjCImpl)
if (requiresForeignTypeMetadata(nominal) ||
(isPrespecialized && !Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) ||
isObjCImpl)
return var;
// Native Swift class metadata has a destructor before the address point.
@@ -5349,6 +5379,10 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
}
}
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
adjustmentIndex = MetadataAdjustmentIndex::EmbeddedWithExistentials;
}
llvm::Constant *indices[] = {
llvm::ConstantInt::get(Int32Ty, 0),
llvm::ConstantInt::get(Int32Ty, adjustmentIndex)};
@@ -5390,7 +5424,10 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
llvm::Type *defaultVarTy;
unsigned adjustmentIndex;
if (concreteType->isAny() || concreteType->isAnyObject() || concreteType->isVoid() || concreteType->is<TupleType>() || concreteType->is<BuiltinType>()) {
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
adjustmentIndex = 0;
defaultVarTy = EmbeddedExistentialsMetadataStructTy;
} else if (concreteType->isAny() || concreteType->isAnyObject() || concreteType->isVoid() || concreteType->is<TupleType>() || concreteType->is<BuiltinType>()) {
defaultVarTy = FullExistentialTypeMetadataStructTy;
adjustmentIndex = MetadataAdjustmentIndex::NoTypeLayoutString;
} else if (fullMetadata) {
@@ -5433,6 +5470,18 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
}
}
}
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
if ((isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) &&
nominal->isGenericContext()) {
IRGen.noteUseOfSpecializedValueMetadata(concreteType);
}
}
}
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials) &&
isa<TupleType>(concreteType)) {
IRGen.noteUseOfSpecializedValueMetadata(concreteType);
}
if (shouldPrespecializeGenericMetadata()) {

View File

@@ -75,6 +75,7 @@
#include "ScalarTypeInfo.h"
#include "StructLayout.h"
#include "StructMetadataVisitor.h"
#include "TupleMetadataVisitor.h"
#include "GenMeta.h"
@@ -2969,7 +2970,10 @@ void irgen::emitLazyTypeContextDescriptor(IRGenModule &IGM,
}
void irgen::emitLazyTypeMetadata(IRGenModule &IGM, NominalTypeDecl *type) {
eraseExistingTypeContextDescriptor(IGM, type);
// Embedded existentials emit very spares metadata records and don't have type
// context descriptors.
if (!type->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials))
eraseExistingTypeContextDescriptor(IGM, type);
if (requiresForeignTypeMetadata(type)) {
emitForeignTypeMetadata(IGM, type);
@@ -4265,6 +4269,9 @@ namespace {
auto type = (Target->checkAncestry(AncestryFlags::ObjC)
? IGM.Context.getAnyObjectType()
: IGM.Context.TheNativeObjectType);
if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
return irgen::emitValueWitnessTable(IGM, type, false, false);
}
auto wtable = IGM.getAddrOfValueWitnessTable(type);
return ConstantReference(wtable,
swift::irgen::ConstantReference::Direct);
@@ -5570,6 +5577,9 @@ void irgen::emitLazyClassMetadata(IRGenModule &IGM, CanType classTy) {
// Might already be emitted, skip if that's the case.
auto entity =
LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::AddressPoint);
if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
entity = LinkEntity::forTypeMetadata(classTy, TypeMetadataAddress::FullMetadata);
}
auto *existingVar = cast<llvm::GlobalVariable>(
IGM.getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo()));
if (!existingVar->isDeclaration()) {
@@ -5597,6 +5607,23 @@ void irgen::emitLazySpecializedClassMetadata(IRGenModule &IGM,
emitEmbeddedVTable(IGM, classTy, vtable);
}
void irgen::emitLazySpecializedValueMetadata(IRGenModule &IGM,
CanType valueTy) {
auto &context = valueTy->getASTContext();
PrettyStackTraceType stackTraceRAII(
context, "emitting lazy specialized value metadata for", valueTy);
if (isa<TupleType>(valueTy)) {
emitLazyTupleMetadata(IGM, valueTy);
} else if (valueTy->getStructOrBoundGenericStruct()) {
emitSpecializedGenericStructMetadata(IGM, valueTy,
*valueTy.getStructOrBoundGenericStruct());
} else {
emitSpecializedGenericEnumMetadata(IGM, valueTy,
*valueTy.getEnumOrBoundGenericEnum());
}
}
void irgen::emitSpecializedGenericClassMetadata(IRGenModule &IGM, CanType type,
ClassDecl &decl) {
assert(decl.isGenericContext());
@@ -6189,7 +6216,10 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) {
bool isPattern;
bool canBeConstant;
bool hasEmbeddedExistentialFeature =
IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials);
if (structDecl->isGenericContext()) {
assert(!hasEmbeddedExistentialFeature);
GenericStructMetadataBuilder builder(IGM, structDecl, init);
builder.layout();
isPattern = true;
@@ -6198,11 +6228,16 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) {
builder.createMetadataAccessFunction();
} else {
StructMetadataBuilder builder(IGM, structDecl, init);
builder.layout();
if (hasEmbeddedExistentialFeature) {
builder.embeddedLayout();
} else {
builder.layout();
}
isPattern = false;
canBeConstant = builder.canBeConstant();
builder.createMetadataAccessFunction();
if (!hasEmbeddedExistentialFeature)
builder.createMetadataAccessFunction();
}
CanType declaredType = structDecl->getDeclaredType()->getCanonicalType();
@@ -6224,13 +6259,74 @@ void irgen::emitSpecializedGenericStructMetadata(IRGenModule &IGM, CanType type,
bool isPattern = false;
SpecializedGenericStructMetadataBuilder builder(IGM, type, decl, init);
builder.layout();
if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
builder.embeddedLayout();
} else {
builder.layout();
}
bool canBeConstant = builder.canBeConstant();
IGM.defineTypeMetadata(type, isPattern, canBeConstant,
init.finishAndCreateFuture());
}
// Tuples (currently only used in embedded existentials mode)
//
namespace {
class TupleMetadataBuilder : public TupleMetadataVisitor<TupleMetadataBuilder> {
using super = TupleMetadataVisitor<TupleMetadataBuilder>;
ConstantStructBuilder &B;
protected:
using super::asImpl;
using super::IGM;
using super::Target;
public:
TupleMetadataBuilder(IRGenModule &IGM, CanType tupleTy, ConstantStructBuilder &B) :
super(IGM, cast<TupleType>(tupleTy)), B(B) {}
ConstantReference emitValueWitnessTable(bool relativeReference) {
return irgen::emitValueWitnessTable(IGM, Target->getCanonicalType(),
false, relativeReference);
}
void addMetadataFlags() {
B.addInt(IGM.MetadataKindTy, unsigned(MetadataKind::Tuple));
}
void addValueWitnessTable() {
auto vwtPointer = emitValueWitnessTable(false).getValue();
B.addSignedPointer(vwtPointer,
IGM.getOptions().PointerAuth.ValueWitnessTable,
PointerAuthEntity());
}
};
} // end anonymous namespace
void irgen::emitLazyTupleMetadata(IRGenModule &IGM, CanType tupleTy) {
assert(IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials));
assert(isa<TupleType>(tupleTy));
Type ty = tupleTy.getPointer();
auto &context = ty->getASTContext();
PrettyStackTraceType stackTraceRAII(
context, "emitting prespecialized metadata for", ty);
ConstantInitBuilder initBuilder(IGM);
auto init = initBuilder.beginStruct();
init.setPacked(true);
bool isPattern = false;
bool canBeConstant = true;
TupleMetadataBuilder builder(IGM, tupleTy, init);
builder.embeddedLayout();
IGM.defineTypeMetadata(tupleTy, isPattern, canBeConstant,
init.finishAndCreateFuture());
}
// Enums
static std::optional<Size>
@@ -6606,7 +6702,10 @@ void irgen::emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum) {
bool isPattern;
bool canBeConstant;
bool hasEmbeddedExistentialFeature =
IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials);
if (theEnum->isGenericContext()) {
assert(!hasEmbeddedExistentialFeature);
GenericEnumMetadataBuilder builder(IGM, theEnum, init);
builder.layout();
isPattern = true;
@@ -6615,11 +6714,16 @@ void irgen::emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum) {
builder.createMetadataAccessFunction();
} else {
EnumMetadataBuilder builder(IGM, theEnum, init);
builder.layout();
if (hasEmbeddedExistentialFeature) {
builder.embeddedLayout();
} else {
builder.layout();
}
isPattern = false;
canBeConstant = builder.canBeConstant();
builder.createMetadataAccessFunction();
if (!hasEmbeddedExistentialFeature)
builder.createMetadataAccessFunction();
}
CanType declaredType = theEnum->getDeclaredType()->getCanonicalType();
@@ -6640,7 +6744,11 @@ void irgen::emitSpecializedGenericEnumMetadata(IRGenModule &IGM, CanType type,
init.setPacked(true);
SpecializedGenericEnumMetadataBuilder builder(IGM, type, decl, init);
builder.layout();
if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
builder.embeddedLayout();
} else {
builder.layout();
}
bool canBeConstant = builder.canBeConstant();
IGM.defineTypeMetadata(type, /*isPattern=*/false, canBeConstant,

View File

@@ -86,6 +86,7 @@ namespace irgen {
void emitLazyClassMetadata(IRGenModule &IGM, CanType classType);
void emitLazySpecializedClassMetadata(IRGenModule &IGM, CanType classType);
void emitLazySpecializedValueMetadata(IRGenModule &IGM, CanType valueTy);
void emitLazyCanonicalSpecializedMetadataAccessor(IRGenModule &IGM,
CanType theType);
@@ -110,6 +111,9 @@ namespace irgen {
void emitSpecializedGenericEnumMetadata(IRGenModule &IGM, CanType type,
EnumDecl &decl);
/// Emit the metadata associated with a given tuple type.
void emitLazyTupleMetadata(IRGenModule &IGM, CanType type);
/// Emit the metadata associated with a given instantiation of a generic
// class.
void emitSpecializedGenericClassMetadata(IRGenModule &IGM, CanType type,
@@ -194,6 +198,12 @@ namespace irgen {
// Class metadata has two words of head-allocated data: the destructor
// and the value witness table.
Class = 3,
// In Embedded with existentials all metadata is a record with a value
// witness prepended.
// -1: vwt
// 0: metadata flags (unused)
EmbeddedWithExistentials = 1,
// Struct and enum metadata have one word of head-allocated data:
// the value witness table.

View File

@@ -1380,17 +1380,24 @@ static void addValueWitnessesForAbstractType(IRGenModule &IGM,
CanType abstractType,
bool &canBeConstant) {
std::optional<BoundGenericTypeCharacteristics> boundGenericCharacteristics;
if (auto boundGenericType = dyn_cast<BoundGenericType>(abstractType)) {
CanType concreteFormalType = getFormalTypeInPrimaryContext(abstractType);
// Embedded existentials need fully "specialized" value witness table
// functions: i.e the metadata argument must remain unused.
// For the non-embedded existentials path, when there is a bound generic type,
// that is we have a specialized generic type, we have decided for code size
// reasons to continue using "generic" value witness table functions i.e the
// same once used for runtime instantiated generic metadata.
if (!IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
if (auto boundGenericType = dyn_cast<BoundGenericType>(abstractType)) {
CanType concreteFormalType = getFormalTypeInPrimaryContext(abstractType);
auto concreteLoweredType = IGM.getLoweredType(concreteFormalType);
const auto *boundConcreteTI = &IGM.getTypeInfo(concreteLoweredType);
auto packing = boundConcreteTI->getFixedPacking(IGM);
boundGenericCharacteristics = {concreteLoweredType, boundConcreteTI,
packing};
abstractType =
boundGenericType->getDecl()->getDeclaredType()->getCanonicalType();
auto concreteLoweredType = IGM.getLoweredType(concreteFormalType);
const auto *boundConcreteTI = &IGM.getTypeInfo(concreteLoweredType);
auto packing = boundConcreteTI->getFixedPacking(IGM);
boundGenericCharacteristics = {concreteLoweredType, boundConcreteTI,
packing};
abstractType =
boundGenericType->getDecl()->getDeclaredType()->getCanonicalType();
}
}
CanType concreteFormalType = getFormalTypeInPrimaryContext(abstractType);
@@ -1533,13 +1540,22 @@ ConstantReference irgen::emitValueWitnessTable(IRGenModule &IGM,
bool isPattern,
bool relativeReference) {
// See if we can use a prefab witness table from the runtime.
if (!isPattern) {
if (!isPattern &&
!IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
if (auto known = getAddrOfKnownValueWitnessTable(IGM, abstractType,
relativeReference)) {
return known;
}
}
// There might already be a definition emitted in embedded mode.
if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
auto addr = IGM.getAddrOfValueWitnessTable(abstractType);
if (!cast<llvm::GlobalVariable>(addr)->isDeclaration()) {
return {addr, ConstantReference::Direct};
}
}
// We should never be making a pattern if the layout isn't fixed.
// The reverse can be true for types whose layout depends on
// resilient types.

View File

@@ -392,6 +392,11 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
TypeMetadataStructTy
});
EmbeddedExistentialsMetadataStructTy = createStructType(*this, "swift.embedded_existential_type", {
WitnessTablePtrTy,
TypeMetadataStructTy
});
// A full heap metadata is basically just an additional small prefix
// on a full metadata, used for metadata corresponding to heap
// allocations.

View File

@@ -349,8 +349,9 @@ private:
llvm::SmallPtrSet<TypeBase *, 4> LazilyEmittedClassMetadata;
llvm::SmallVector<CanType, 4> LazySpecializedClassMetadata;
llvm::SmallVector<CanType, 4> LazySpecializedValueMetadata;
llvm::SmallPtrSet<TypeBase *, 4> LazilyEmittedSpecializedClassMetadata;
llvm::SmallPtrSet<TypeBase *, 4> LazilyEmittedSpecializedMetadata;
llvm::SmallVector<ClassDecl *, 4> ClassesForEagerInitialization;
@@ -509,6 +510,7 @@ public:
void noteUseOfClassMetadata(CanType classType);
void noteUseOfSpecializedClassMetadata(CanType classType);
void noteUseOfSpecializedValueMetadata(CanType valueType);
void noteUseOfTypeMetadata(NominalTypeDecl *type) {
noteUseOfTypeGlobals(type, true, RequireMetadata);
@@ -828,6 +830,7 @@ public:
llvm::StructType *TupleTypeMetadataTy; /// %swift.tuple_type
llvm::StructType *FullHeapMetadataStructTy; /// %swift.full_heapmetadata = type { ... }
llvm::StructType *FullBoxMetadataStructTy; /// %swift.full_boxmetadata = type { ... }
llvm::StructType *EmbeddedExistentialsMetadataStructTy;
llvm::StructType *FullTypeMetadataStructTy; /// %swift.full_type = type { ... }
llvm::StructType *FullExistentialTypeMetadataStructTy; /// %swift.full_existential_type = type { ... }
llvm::StructType *FullForeignTypeMetadataStructTy; /// %swift.full_foreign_type = type { ... }

View File

@@ -696,6 +696,12 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
if (isForcedShared())
return SILLinkage::Shared;
// In embedded existenitals mode we generate metadata for tuple types.
if (getType()->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials) &&
isa<TupleType>(getType())) {
return SILLinkage::Shared;
}
auto *nominal = getType().getAnyNominal();
switch (getMetadataAddress()) {
case TypeMetadataAddress::FullMetadata:
@@ -1120,6 +1126,9 @@ llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const {
case Kind::NoncanonicalSpecializedGenericTypeMetadata:
switch (getMetadataAddress()) {
case TypeMetadataAddress::FullMetadata:
if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
return IGM.EmbeddedExistentialsMetadataStructTy;
}
if (getType().getClassOrBoundGenericClass())
return IGM.FullHeapMetadataStructTy;
else

View File

@@ -886,6 +886,17 @@ bool irgen::isCompleteSpecializedNominalTypeMetadataStaticallyAddressable(
return false;
}
if (IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials) &&
(isa<StructType>(type) || isa<BoundGenericStructType>(type) ||
isa<EnumType>(type) || isa<BoundGenericEnumType>(type))) {
if (type->hasArchetype()) {
llvm::errs() << "Cannot get metadata of generic class for type "
<< type << "\n";
llvm::report_fatal_error("cannot get metadata for type with archetype");
}
return true;
}
// Prespecialized struct/enum metadata gets no dedicated accessor yet and so
// cannot do the work of registering the generic arguments which are classes
// with the ObjC runtime. Concretely, the following cannot be prespecialized
@@ -1252,6 +1263,10 @@ static MetadataResponse emitFixedArrayMetadataRef(IRGenFunction &IGF,
static MetadataResponse emitTupleTypeMetadataRef(IRGenFunction &IGF,
CanTupleType type,
DynamicMetadataRequest request) {
if (IGF.IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
return MetadataResponse::forComplete(IGF.IGM.getAddrOfTypeMetadata(type));
}
if (type->containsPackExpansionType())
return emitDynamicTupleTypeMetadataRef(IGF, type, request);
@@ -3373,6 +3388,7 @@ MetadataResponse
IRGenFunction::emitTypeMetadataRef(CanType type,
DynamicMetadataRequest request) {
if (type->getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
!type->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials) &&
!isMetadataAllowedInEmbedded(type)) {
llvm::errs() << "Metadata pointer requested in embedded Swift for type "
<< type << "\n";

View File

@@ -43,6 +43,14 @@ protected:
: super(IGM), Target(target) {}
public:
void embeddedLayout() {
// The embedded layout consists of:
// -1 : vwt
// 0 : metadata flags
super::layout();
}
void layout() {
static_assert(MetadataAdjustmentIndex::ValueType == 2,
"Adjustment index must be synchronized with this layout");

View File

@@ -39,6 +39,14 @@ protected:
: super(IGM), Target(target) {}
public:
void embeddedLayout() {
// The embedded layout consists of:
// -1 : vwt
// 0 : metadata flags
super::layout();
}
void layout() {
super::layout();

View File

@@ -1,23 +1,78 @@
// RUN: %target-swift-frontend -enable-experimental-feature EmbeddedExistentials -enable-experimental-feature Embedded -parse-as-library -wmo -emit-sil %s | %FileCheck %s
// RUN: %target-run-simple-swift(-enable-experimental-feature EmbeddedExistentials -enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s --check-prefix=OUTPUT
// REQUIRES: swift_in_compiler
// REQUIRES: executable_test
// REQUIRES: optimized_stdlib
// REQUIRES: swift_feature_Embedded
// REQUIRES: swift_feature_EmbeddedExistentials
class C {}
class CP {
}
class C : CP {
func foo() { }
}
class GC<T> {
var x: T? = nil
func foo() {}
deinit {
print("deinit called")
}
}
struct StructWithClass {
var c = GC<Int>()
}
struct GenericStructWithClass<T> {
var c = GC<T>()
var d = GC<T>()
}
enum EnumWithClass {
case a
case c(GC<Int>)
}
enum GenericEnumWithClass<T> {
case a
case c(GC<T>)
}
// CHECK: sil @$e11existential4testyyF
// CHECK: init_existential_addr
// CHECK: } // end sil function '$e11existential4testyyF'
// There are 8 class instances that are destroyed.
// OUTPUT: deinit called
// OUTPUT: deinit called
// OUTPUT: deinit called
// OUTPUT: deinit called
// OUTPUT: deinit called
// OUTPUT: deinit called
// OUTPUT: deinit called
// OUTPUT: deinit called
// OUTPUT-NOT: deinit called
func test() {
let any: any Any = C()
let _: any Any = GC<Int>()
let _: any Any = 3
let _: any Any = StructWithClass()
let _: any Any = GenericStructWithClass<Int>()
let _: any Any = EnumWithClass.c(GC<Int>())
let _: any Any = GenericEnumWithClass.c(GC<Int>())
let _: any Any = (3, 4)
let _: any Any = (StructWithClass(), StructWithClass())
}
@main
struct Main {
static func main() {
test()
}
static func main() {
test()
}
}