mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
IRGen: Start support for embedded existentials
Allow storing struct, enum, and tuple types in an any.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 { ... }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user