Skip to content
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
21 changes: 18 additions & 3 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,18 @@ enum class TypeMetadataAddress {
inline bool isEmbedded(CanType t) {
return t->getASTContext().LangOpts.hasFeature(Feature::Embedded);
}

inline bool isEmbeddedWithoutEmbeddedExitentials(CanType t) {
auto &langOpts = t->getASTContext().LangOpts;
return langOpts.hasFeature(Feature::Embedded) &&
!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;
Expand All @@ -106,6 +113,9 @@ inline bool isMetadataAllowedInEmbedded(CanType t) {
if (archeTy->requiresClass())
return true;
}

if (embeddedExistentials)
return true;
return false;
}

Expand All @@ -117,6 +127,11 @@ inline bool isEmbedded(const ProtocolConformance *c) {
return c->getType()->getASTContext().LangOpts.hasFeature(Feature::Embedded);
}

inline bool isEmbeddedWithoutEmbeddedExitentials(const ProtocolConformance *c) {
return isEmbedded(c) && !c->getType()->getASTContext().
LangOpts.hasFeature(Feature::EmbeddedExistentials);
}

/// A link entity is some sort of named declaration, combined with all
/// the information necessary to distinguish specific implementations
/// of the declaration from each other.
Expand Down Expand Up @@ -1098,7 +1113,7 @@ class LinkEntity {
}

static LinkEntity forValueWitnessTable(CanType type) {
assert(!isEmbedded(type));
assert(!isEmbeddedWithoutEmbeddedExitentials(type));
LinkEntity entity;
entity.setForType(Kind::ValueWitnessTable, type);
return entity;
Expand Down Expand Up @@ -1128,7 +1143,7 @@ class LinkEntity {
}

static LinkEntity forProtocolWitnessTable(const ProtocolConformance *C) {
if (isEmbedded(C)) {
if (isEmbeddedWithoutEmbeddedExitentials(C)) {
assert(C->getProtocol()->requiresClass());
}

Expand Down
8 changes: 8 additions & 0 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,14 @@ FUNCTION(NativeStrongReleaseDirect, Swift, swift_releaseDirect, SwiftDirectRR_CC
EFFECT(RuntimeEffect::RefCounting, RuntimeEffect::Deallocating),
UNKNOWN_MEMEFFECTS)

// void swift_releaseBox(void *ptr);
FUNCTION(ReleaseBox, Swift, swift_releaseBox, C_CC, AlwaysAvailable,
RETURNS(VoidTy),
ARGS(RefCountedPtrTy),
ATTRS(NoUnwind),
EFFECT(RuntimeEffect::RefCounting, RuntimeEffect::Deallocating),
UNKNOWN_MEMEFFECTS)

// void *swift_retain_n(void *ptr, int32_t n);
FUNCTION(NativeStrongRetainN, Swift, swift_retain_n, C_CC, AlwaysAvailable,
RETURNS(RefCountedPtrTy),
Expand Down
4 changes: 4 additions & 0 deletions lib/IRGen/ClassMetadataVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ template <class Impl> class ClassMetadataVisitor
// 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();
Expand All @@ -89,6 +91,8 @@ template <class Impl> class ClassMetadataVisitor
"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();
Expand Down
8 changes: 8 additions & 0 deletions lib/IRGen/EnumMetadataVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ template <class Impl> class EnumMetadataVisitor
: 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");
Expand Down
63 changes: 56 additions & 7 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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()) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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())) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -5298,6 +5321,9 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
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),
Expand All @@ -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;
}

Expand All @@ -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.
Expand All @@ -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)};
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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()) {
Expand Down
20 changes: 19 additions & 1 deletion lib/IRGen/GenExistential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2314,7 +2314,21 @@ Address irgen::emitAllocateBoxedOpaqueExistentialBuffer(
if (fixedTI->getFixedPacking(IGF.IGM) == FixedPacking::OffsetZero) {
return valueTI.getAddressForPointer(IGF.Builder.CreateBitCast(
existentialBuffer.getAddress(), IGF.IGM.PtrTy));
} else if (IGF.IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
llvm::Value *box, *address;
auto *metadata = existLayout.loadMetadataRef(IGF, existentialContainer);
IGF.emitAllocBoxCall(metadata, box, address);
llvm::Value *addressInBox =
IGF.Builder.CreateBitCast(address, IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateStore(
box, Address(IGF.Builder.CreateBitCast(
existentialBuffer.getAddress(), IGF.IGM.PtrTy),
IGF.IGM.RefCountedPtrTy,
existLayout.getAlignment(IGF.IGM)));

return valueTI.getAddressForPointer(addressInBox);
}

// Otherwise, allocate a box with enough storage.
Address addr = emitAllocateExistentialBoxInBuffer(
IGF, valueType, existentialBuffer, genericEnv, "exist.box.addr",
Expand Down Expand Up @@ -2883,7 +2897,11 @@ static llvm::Function *getDestroyBoxedOpaqueExistentialBufferFunction(
Builder.CreateBitCast(buffer.getAddress(), IGM.PtrTy);
auto *reference = Builder.CreateLoad(Address(
referenceAddr, IGM.RefCountedPtrTy, buffer.getAlignment()));
IGF.emitNativeStrongRelease(reference, IGF.getDefaultAtomicity());
if (IGF.IGM.Context.LangOpts
.hasFeature(Feature::EmbeddedExistentials)) {
IGF.emitReleaseBox(reference);
} else
IGF.emitNativeStrongRelease(reference, IGF.getDefaultAtomicity());

Builder.CreateRetVoid();
}
Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/GenHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,12 @@ void IRGenFunction::emitNativeStrongRelease(llvm::Value *value,
emitUnaryRefCountCall(*this, function, value);
}

void IRGenFunction::emitReleaseBox(llvm::Value *value) {
if (doesNotRequireRefCounting(value))
return;
emitUnaryRefCountCall(*this, IGM.getReleaseBoxFn(), value);
}

void IRGenFunction::emitNativeSetDeallocating(llvm::Value *value) {
if (doesNotRequireRefCounting(value)) return;
emitUnaryRefCountCall(*this, IGM.getNativeSetDeallocatingFn(), value);
Expand Down
Loading