diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 05a97216cd5..24fa49f81b7 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -361,248 +361,88 @@ FUNCTION(ErrorStrongRelease, swift_errorRelease, C_CC, ARGS(ErrorPtrTy), ATTRS(NoUnwind)) -// void *swift_unownedRetain(void *ptr); -FUNCTION(NativeUnownedRetain, swift_unownedRetain, C_CC, - RETURNS(RefCountedPtrTy), - ARGS(RefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void swift_unownedRelease(void *ptr); -FUNCTION(NativeUnownedRelease, swift_unownedRelease, C_CC, - RETURNS(VoidTy), - ARGS(RefCountedPtrTy), - ATTRS(NoUnwind)) - -// void *swift_nonatomic_unownedRetain(void *ptr); -FUNCTION(NonAtomicNativeUnownedRetain, swift_nonatomic_unownedRetain, - C_CC, - RETURNS(RefCountedPtrTy), - ARGS(RefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void swift_nonatomic_unownedRelease(void *ptr); -FUNCTION(NonAtomicNativeUnownedRelease, swift_nonatomic_unownedRelease, - C_CC, - RETURNS(VoidTy), - ARGS(RefCountedPtrTy), - ATTRS(NoUnwind)) - -// void *swift_unownedRetain_n(void *ptr, int32_t n); -FUNCTION(UnownedRetainN, swift_unownedRetain_n, - C_CC, - RETURNS(RefCountedPtrTy), - ARGS(RefCountedPtrTy, Int32Ty), - ATTRS(NoUnwind, FirstParamReturned)) - -// void swift_unownedRelease_n(void *ptr, int32_t n); -FUNCTION(UnownedReleaseN, swift_unownedRelease_n, - C_CC, - RETURNS(VoidTy), - ARGS(RefCountedPtrTy, Int32Ty), - ATTRS(NoUnwind)) - -// void *swift_nonatomic_unownedRetain_n(void *ptr, int32_t n); -FUNCTION(NonAtomicUnownedRetainN, swift_nonatomic_unownedRetain_n, - C_CC, - RETURNS(RefCountedPtrTy), - ARGS(RefCountedPtrTy, Int32Ty), - ATTRS(NoUnwind, FirstParamReturned)) - -// void swift_nonatomic_unownedRelease_n(void *ptr, int32_t n); -FUNCTION(NonAtomicUnownedReleaseN, swift_nonatomic_unownedRelease_n, - C_CC, - RETURNS(VoidTy), - ARGS(RefCountedPtrTy, Int32Ty), - ATTRS(NoUnwind)) - -// void *swift_unownedRetainStrong(void *ptr); -FUNCTION(NativeStrongRetainUnowned, swift_unownedRetainStrong, C_CC, - RETURNS(RefCountedPtrTy), - ARGS(RefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void *swift_nonatomic_unownedRetainStrong(void *ptr); -FUNCTION(NonAtomicNativeStrongRetainUnowned, swift_nonatomic_unownedRetainStrong, - C_CC, - RETURNS(RefCountedPtrTy), - ARGS(RefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void swift_unownedRetainStrongAndRelease(void *ptr); -FUNCTION(NativeStrongRetainAndUnownedRelease, - swift_unownedRetainStrongAndRelease, C_CC, - RETURNS(VoidTy), - ARGS(RefCountedPtrTy), - ATTRS(NoUnwind)) - -// void swift_nonatomic_unownedRetainStrongAndRelease(void *ptr); -FUNCTION(NonAtomicNativeStrongRetainAndUnownedRelease, - swift_nonatomic_unownedRetainStrongAndRelease, C_CC, - RETURNS(VoidTy), - ARGS(RefCountedPtrTy), - ATTRS(NoUnwind)) - -// void swift_weakDestroy(WeakReference *object); -FUNCTION(NativeWeakDestroy, swift_weakDestroy, C_CC, - RETURNS(VoidTy), - ARGS(WeakReferencePtrTy), - ATTRS(NoUnwind)) - -// WeakReference *swift_weakInit(WeakReference *object, void *value); -FUNCTION(NativeWeakInit, swift_weakInit, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, RefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// WeakReference *swift_weakAssign(WeakReference *object, void *value); -FUNCTION(NativeWeakAssign, swift_weakAssign, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, RefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void *swift_weakLoadStrong(WeakReference *object); -FUNCTION(NativeWeakLoadStrong, swift_weakLoadStrong,C_CC, - RETURNS(RefCountedPtrTy), - ARGS(WeakReferencePtrTy), - ATTRS(NoUnwind)) - -// void *swift_weakTakeStrong(WeakReference *object); -FUNCTION(NativeWeakTakeStrong, swift_weakTakeStrong,C_CC, - RETURNS(RefCountedPtrTy), - ARGS(WeakReferencePtrTy), - ATTRS(NoUnwind)) - -// WeakReference *swift_weakCopyInit(WeakReference *dest, WeakReference *src); -FUNCTION(NativeWeakCopyInit, swift_weakCopyInit, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, WeakReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// WeakReference *swift_weakTakeInit(WeakReference *dest, WeakReference *src); -FUNCTION(NativeWeakTakeInit, swift_weakTakeInit, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, WeakReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// WeakReference *swift_weakCopyAssign(WeakReference *dest, WeakReference *src); -FUNCTION(NativeWeakCopyAssign, swift_weakCopyAssign, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, WeakReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// WeakReference *swift_weakTakeAssign(WeakReference *dest, WeakReference *src); -FUNCTION(NativeWeakTakeAssign, swift_weakTakeAssign, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, WeakReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void swift_unknownWeakDestroy(WeakReference *object); -FUNCTION(UnknownWeakDestroy, swift_unknownWeakDestroy, C_CC, - RETURNS(VoidTy), - ARGS(WeakReferencePtrTy), - ATTRS(NoUnwind)) - -// void swift_unknownWeakInit(WeakReference *object, void *value); -FUNCTION(UnknownWeakInit, swift_unknownWeakInit, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, UnknownRefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// WeakReference *swift_unknownWeakAssign(WeakReference *object, void *value); -FUNCTION(UnknownWeakAssign, swift_unknownWeakAssign, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, UnknownRefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void *swift_unknownWeakLoad(WeakReference *object); -FUNCTION(UnknownWeakLoadStrong, swift_unknownWeakLoadStrong,C_CC, - RETURNS(UnknownRefCountedPtrTy), - ARGS(WeakReferencePtrTy), - ATTRS(NoUnwind)) - -// void *swift_unknownWeakTake(WeakReference *object); -FUNCTION(UnknownWeakTakeStrong, swift_unknownWeakTakeStrong,C_CC, - RETURNS(UnknownRefCountedPtrTy), - ARGS(WeakReferencePtrTy), - ATTRS(NoUnwind)) - -// WeakReference *swift_unknownWeakCopyInit(WeakReference *dest, WeakReference *src); -FUNCTION(UnknownWeakCopyInit, swift_unknownWeakCopyInit, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, WeakReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void *swift_unknownWeakTakeInit(WeakReference *dest, WeakReference *src); -FUNCTION(UnknownWeakTakeInit, swift_unknownWeakTakeInit, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, WeakReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// WeakReference *swift_unknownWeakCopyAssign(WeakReference *dest, WeakReference *src); -FUNCTION(UnknownWeakCopyAssign, swift_unknownWeakCopyAssign, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, WeakReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// WeakReference *swift_unknownWeakTakeAssign(WeakReference *dest, WeakReference *src); -FUNCTION(UnknownWeakTakeAssign, swift_unknownWeakTakeAssign, C_CC, - RETURNS(WeakReferencePtrTy), - ARGS(WeakReferencePtrTy, WeakReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void swift_unknownUnownedDestroy(UnownedReference *object); -FUNCTION(UnknownUnownedDestroy, swift_unknownUnownedDestroy, C_CC, - RETURNS(VoidTy), - ARGS(UnownedReferencePtrTy), - ATTRS(NoUnwind)) - -// UnownedReference *swift_unknownUnownedInit(UnownedReference *object, void *value); -FUNCTION(UnknownUnownedInit, swift_unknownUnownedInit, C_CC, - RETURNS(UnownedReferencePtrTy), - ARGS(UnownedReferencePtrTy, UnknownRefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// UnownedReference *swift_unknownUnownedAssign(UnownedReference *object, void *value); -FUNCTION(UnknownUnownedAssign, swift_unknownUnownedAssign, C_CC, - RETURNS(UnownedReferencePtrTy), - ARGS(UnownedReferencePtrTy, UnknownRefCountedPtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// void *swift_unknownUnownedLoad(UnownedReference *object); -FUNCTION(UnknownUnownedLoadStrong, swift_unknownUnownedLoadStrong, C_CC, - RETURNS(UnknownRefCountedPtrTy), - ARGS(UnownedReferencePtrTy), - ATTRS(NoUnwind)) - -// void *swift_unknownUnownedTake(UnownedReference *object); -FUNCTION(UnknownUnownedTakeStrong, swift_unknownUnownedTakeStrong, C_CC, - RETURNS(UnknownRefCountedPtrTy), - ARGS(UnownedReferencePtrTy), - ATTRS(NoUnwind)) - -// UnownedReference *swift_unknownUnownedCopyInit(UnownedReference *dest, UnownedReference *src); -FUNCTION(UnknownUnownedCopyInit, swift_unknownUnownedCopyInit, C_CC, - RETURNS(UnownedReferencePtrTy), - ARGS(UnownedReferencePtrTy, UnownedReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// UnownedReference *swift_unknownUnownedTakeInit(UnownedReference *dest, UnownedReference *src); -FUNCTION(UnknownUnownedTakeInit, swift_unknownUnownedTakeInit, C_CC, - RETURNS(UnownedReferencePtrTy), - ARGS(UnownedReferencePtrTy, UnownedReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// UnownedReference *swift_unknownUnownedCopyAssign(UnownedReference *dest, UnownedReference *src); -FUNCTION(UnknownUnownedCopyAssign, swift_unknownUnownedCopyAssign, C_CC, - RETURNS(UnownedReferencePtrTy), - ARGS(UnownedReferencePtrTy, UnownedReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) - -// UnownedReference *swift_unknownUnownedTakeAssign(UnownedReference *dest, UnownedReference *src); -FUNCTION(UnknownUnownedTakeAssign, swift_unknownUnownedTakeAssign, C_CC, - RETURNS(UnownedReferencePtrTy), - ARGS(UnownedReferencePtrTy, UnownedReferencePtrTy), - ATTRS(NoUnwind, FirstParamReturned)) +#define NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Nativeness, SymName, UnknownPrefix) \ + /* void swift_##SymName##Destroy(Name##Reference *object); */ \ + FUNCTION(Nativeness##Name##Destroy, swift_##SymName##Destroy, C_CC, \ + RETURNS(VoidTy), \ + ARGS(Name##ReferencePtrTy), \ + ATTRS(NoUnwind)) \ + /* void swift_##SymName##Init(Name##Reference *object, void *value); */ \ + FUNCTION(Nativeness##Name##Init, swift_##SymName##Init, C_CC, \ + RETURNS(Name##ReferencePtrTy), \ + ARGS(Name##ReferencePtrTy, UnknownPrefix##RefCountedPtrTy), \ + ATTRS(NoUnwind, FirstParamReturned)) \ + /* Name##Reference *swift_##SymName##Assign(Name##Reference *object, void *value); */ \ + FUNCTION(Nativeness##Name##Assign, swift_##SymName##Assign, C_CC, \ + RETURNS(Name##ReferencePtrTy), \ + ARGS(Name##ReferencePtrTy, UnknownPrefix##RefCountedPtrTy), \ + ATTRS(NoUnwind, FirstParamReturned)) \ + /* void *swift_##SymName##Load(Name##Reference *object); */ \ + FUNCTION(Nativeness##Name##LoadStrong, swift_##SymName##LoadStrong,C_CC, \ + RETURNS(UnknownPrefix##RefCountedPtrTy), \ + ARGS(Name##ReferencePtrTy), \ + ATTRS(NoUnwind)) \ + /* void *swift_##SymName##Take(Name##Reference *object); */ \ + FUNCTION(Nativeness##Name##TakeStrong, swift_##SymName##TakeStrong,C_CC, \ + RETURNS(UnknownPrefix##RefCountedPtrTy), \ + ARGS(Name##ReferencePtrTy), \ + ATTRS(NoUnwind)) \ + /* Name##Reference *swift_##SymName##CopyInit(Name##Reference *dest, Name##Reference *src); */ \ + FUNCTION(Nativeness##Name##CopyInit, swift_##SymName##CopyInit, C_CC, \ + RETURNS(Name##ReferencePtrTy), \ + ARGS(Name##ReferencePtrTy, Name##ReferencePtrTy), \ + ATTRS(NoUnwind, FirstParamReturned)) \ + /* void *swift_##SymName##TakeInit(Name##Reference *dest, Name##Reference *src); */ \ + FUNCTION(Nativeness##Name##TakeInit, swift_##SymName##TakeInit, C_CC, \ + RETURNS(Name##ReferencePtrTy), \ + ARGS(Name##ReferencePtrTy, Name##ReferencePtrTy), \ + ATTRS(NoUnwind, FirstParamReturned)) \ + /* Name##Reference *swift_##SymName##CopyAssign(Name##Reference *dest, Name##Reference *src); */ \ + FUNCTION(Nativeness##Name##CopyAssign, swift_##SymName##CopyAssign, C_CC, \ + RETURNS(Name##ReferencePtrTy), \ + ARGS(Name##ReferencePtrTy, Name##ReferencePtrTy), \ + ATTRS(NoUnwind, FirstParamReturned)) \ + /* Name##Reference *swift_##SymName##TakeAssign(Name##Reference *dest, Name##Reference *src); */ \ + FUNCTION(Nativeness##Name##TakeAssign, swift_##SymName##TakeAssign, C_CC, \ + RETURNS(Name##ReferencePtrTy), \ + ARGS(Name##ReferencePtrTy, Name##ReferencePtrTy), \ + ATTRS(NoUnwind, FirstParamReturned)) +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Native, name, ) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Unknown, unknown##Name, Unknown) +#define LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name, Prefix, prefix) \ + /* void *swift_##prefix##name##Retain(void *ptr); */ \ + FUNCTION(Prefix##Name##Retain, swift_##prefix##name##Retain, C_CC, \ + RETURNS(RefCountedPtrTy), \ + ARGS(RefCountedPtrTy), \ + ATTRS(NoUnwind, FirstParamReturned)) \ + /* void swift_##prefix##name##Release(void *ptr); */ \ + FUNCTION(Prefix##Name##Release, swift_##prefix##name##Release, C_CC, \ + RETURNS(VoidTy), \ + ARGS(RefCountedPtrTy), \ + ATTRS(NoUnwind)) \ + /* void *swift_##prefix##name##RetainStrong(void *ptr); */ \ + FUNCTION(Prefix##StrongRetain##Name, swift_##prefix##name##RetainStrong, \ + C_CC, \ + RETURNS(RefCountedPtrTy), \ + ARGS(RefCountedPtrTy), \ + ATTRS(NoUnwind, FirstParamReturned)) \ + /* void swift_##prefix##name##RetainStrongAndRelease(void *ptr); */ \ + FUNCTION(Prefix##StrongRetainAnd##Name##Release, \ + swift_##prefix##name##RetainStrongAndRelease, C_CC, \ + RETURNS(VoidTy), \ + ARGS(RefCountedPtrTy), \ + ATTRS(NoUnwind)) +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Unknown, unknown##Name, Unknown) \ + LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name, Native, ) \ + LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name, NonAtomicNative, nonatomic_) +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name, Native, ) \ + LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name, NonAtomicNative, nonatomic_) +#include "swift/AST/ReferenceStorage.def" +#undef NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER +#undef LOADABLE_CHECKED_REF_STORAGE_HELPER // bool swift_isUniquelyReferencedNonObjC(const void *); FUNCTION(IsUniquelyReferencedNonObjC, swift_isUniquelyReferencedNonObjC, diff --git a/lib/IRGen/ExtraInhabitants.cpp b/lib/IRGen/ExtraInhabitants.cpp index 0d20441170c..7805656867a 100644 --- a/lib/IRGen/ExtraInhabitants.cpp +++ b/lib/IRGen/ExtraInhabitants.cpp @@ -23,7 +23,7 @@ using namespace swift; using namespace irgen; -static unsigned getNumLowObjCReservedBits(IRGenModule &IGM) { +static unsigned getNumLowObjCReservedBits(const IRGenModule &IGM) { if (!IGM.ObjCInterop) return 0; @@ -37,7 +37,7 @@ static unsigned getNumLowObjCReservedBits(IRGenModule &IGM) { /// Return the number of extra inhabitants for a pointer that reserves /// the given number of low bits. -static unsigned getPointerExtraInhabitantCount(IRGenModule &IGM, +static unsigned getPointerExtraInhabitantCount(const IRGenModule &IGM, unsigned numReservedLowBits) { // FIXME: We could also make extra inhabitants using spare bits, but we // probably don't need to. @@ -48,7 +48,7 @@ static unsigned getPointerExtraInhabitantCount(IRGenModule &IGM, return std::min((uint64_t)INT_MAX, rawCount); } -unsigned irgen::getHeapObjectExtraInhabitantCount(IRGenModule &IGM) { +unsigned irgen::getHeapObjectExtraInhabitantCount(const IRGenModule &IGM) { // This must be consistent with the extra inhabitant count produced // by the runtime's getHeapObjectExtraInhabitantCount function in // KnownMetadata.cpp. @@ -62,7 +62,7 @@ unsigned irgen::getFunctionPointerExtraInhabitantCount(IRGenModule &IGM) { /*****************************************************************************/ static APInt -getPointerFixedExtraInhabitantValue(IRGenModule &IGM, unsigned bits, +getPointerFixedExtraInhabitantValue(const IRGenModule &IGM, unsigned bits, unsigned index, unsigned offset, unsigned numReservedLowBits) { assert(index < getPointerExtraInhabitantCount(IGM, numReservedLowBits) && @@ -75,7 +75,7 @@ getPointerFixedExtraInhabitantValue(IRGenModule &IGM, unsigned bits, return apValue; } -APInt irgen::getHeapObjectFixedExtraInhabitantValue(IRGenModule &IGM, +APInt irgen::getHeapObjectFixedExtraInhabitantValue(const IRGenModule &IGM, unsigned bits, unsigned index, unsigned offset) { diff --git a/lib/IRGen/ExtraInhabitants.h b/lib/IRGen/ExtraInhabitants.h index e4ebd12ac32..3b13d35dc48 100644 --- a/lib/IRGen/ExtraInhabitants.h +++ b/lib/IRGen/ExtraInhabitants.h @@ -37,14 +37,14 @@ class IRGenModule; /// Return the number of extra inhabitant representations for heap objects, /// that is, the number of invalid heap object pointer values that can be used /// to represent enum tags for enums involving a reference type as a payload. -unsigned getHeapObjectExtraInhabitantCount(IRGenModule &IGM); +unsigned getHeapObjectExtraInhabitantCount(const IRGenModule &IGM); /// Return an indexed extra inhabitant constant for a heap object pointer. /// /// If the pointer appears within a larger aggregate, the 'bits' and 'offset' /// arguments can be used to position the inhabitant within the larger integer /// constant. -llvm::APInt getHeapObjectFixedExtraInhabitantValue(IRGenModule &IGM, +llvm::APInt getHeapObjectFixedExtraInhabitantValue(const IRGenModule &IGM, unsigned bits, unsigned index, unsigned offset); diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp index 27f50f8cf96..2e7fffaca57 100644 --- a/lib/IRGen/GenArchetype.cpp +++ b/lib/IRGen/GenArchetype.cpp @@ -49,7 +49,6 @@ #include "ProtocolInfo.h" #include "ResilientTypeInfo.h" #include "TypeInfo.h" -#include "WeakTypeInfo.h" using namespace swift; using namespace irgen; diff --git a/lib/IRGen/GenExistential.cpp b/lib/IRGen/GenExistential.cpp index e7e5fb5c40a..0d702091d8f 100644 --- a/lib/IRGen/GenExistential.cpp +++ b/lib/IRGen/GenExistential.cpp @@ -50,7 +50,6 @@ #include "Outlining.h" #include "ProtocolInfo.h" #include "TypeInfo.h" -#include "WeakTypeInfo.h" using namespace swift; using namespace irgen; @@ -117,6 +116,694 @@ namespace { return IGF.Builder.CreateLoad(projectMetadataRef(IGF, addr)); } }; + + /// A helper class for implementing existential type infos that + /// store an existential value of some sort. + template + class ExistentialTypeInfoBase : public Base, + private llvm::TrailingObjects { + friend class llvm::TrailingObjects; + + /// The number of non-trivial protocols for this existential. + unsigned NumStoredProtocols; + + protected: + const Derived &asDerived() const { + return *static_cast(this); + } + Derived &asDerived() { + return *static_cast(this); + } + + template + ExistentialTypeInfoBase(ArrayRef protocols, + As &&...args) + : Base(std::forward(args)...), + NumStoredProtocols(protocols.size()) { + std::uninitialized_copy(protocols.begin(), protocols.end(), + this->template getTrailingObjects()); + } + + public: + template + static const Derived * + create(ArrayRef protocols, As &&...args) + { + void *buffer = + operator new(ExistentialTypeInfoBase::template totalSizeToAlloc(protocols.size())); + return new (buffer) Derived(protocols, std::forward(args)...); + } + + /// Returns the number of protocol witness tables directly carried + /// by values of this type. + unsigned getNumStoredProtocols() const { return NumStoredProtocols; } + + /// Returns the protocols that values of this type are known to + /// implement. This can be empty, meaning that values of this + /// type are not know to implement any protocols, although we do + /// still know how to manipulate them. + ArrayRef getStoredProtocols() const { + return {this->template getTrailingObjects(), + NumStoredProtocols}; + } + + /// Given an existential object, find the witness table + /// corresponding to the given protocol. + llvm::Value *findWitnessTable(IRGenFunction &IGF, + Explosion &container, + ProtocolDecl *protocol) const { + assert(NumStoredProtocols != 0 && + "finding a witness table in a trivial existential"); + + return emitImpliedWitnessTableRef(IGF, getStoredProtocols(), protocol, + [&](unsigned originIndex) { + return asDerived().extractWitnessTable(IGF, container, originIndex); + }); + } + + /// Given the address of an existential object, find the witness + /// table corresponding to the given protocol. + llvm::Value *findWitnessTable(IRGenFunction &IGF, Address obj, + ProtocolDecl *protocol) const { + assert(NumStoredProtocols != 0 && + "finding a witness table in a trivial existential"); + + return emitImpliedWitnessTableRef(IGF, getStoredProtocols(), protocol, + [&](unsigned originIndex) { + return asDerived().loadWitnessTable(IGF, obj, originIndex); + }); + } + + /// Given the witness table vector from an existential object, find the + /// witness table corresponding to the given protocol. + llvm::Value *findWitnessTable(IRGenFunction &IGF, + ArrayRef witnesses, + ProtocolDecl *protocol) const { + return emitImpliedWitnessTableRef(IGF, getStoredProtocols(), protocol, + [&](unsigned originIndex) { + return witnesses[originIndex]; + }); + } + + /// Given the address of an existential object, find the witness + /// table of a directly-stored witness table. + llvm::Value *loadWitnessTable(IRGenFunction &IGF, Address obj, + unsigned which) const { + return IGF.Builder.CreateLoad( + asDerived().projectWitnessTable(IGF, obj, which)); + } + + void emitCopyOfTables(IRGenFunction &IGF, Address dest, Address src) const { + if (NumStoredProtocols == 0) return; + + Explosion temp; + asDerived().emitLoadOfTables(IGF, src, temp); + asDerived().emitStoreOfTables(IGF, temp, dest); + } + + void emitLoadOfTables(IRGenFunction &IGF, Address existential, + Explosion &out) const { + for (unsigned i = 0; i != NumStoredProtocols; ++i) { + auto tableAddr = asDerived().projectWitnessTable(IGF, existential, i); + out.add(IGF.Builder.CreateLoad(tableAddr)); + } + } + + void emitStoreOfTables(IRGenFunction &IGF, Explosion &in, + Address existential) const { + for (unsigned i = 0; i != NumStoredProtocols; ++i) { + auto tableAddr = asDerived().projectWitnessTable(IGF, existential, i); + IGF.Builder.CreateStore(in.claimNext(), tableAddr); + } + } + }; + + /// A type implementation for address-only reference storage of + /// class existential types. + template + class AddressOnlyClassExistentialTypeInfoBase : + public ExistentialTypeInfoBase> { + using super = ExistentialTypeInfoBase>; + + using super::asDerived; + using super::emitCopyOfTables; + using super::getNumStoredProtocols; + + protected: + const ReferenceCounting Refcounting; + + template + AddressOnlyClassExistentialTypeInfoBase(ArrayRef protocols, + ReferenceCounting refcounting, + As &&...args) + : super(protocols, std::forward(args)...), + Refcounting(refcounting) { + } + + public: + Address projectWitnessTable(IRGenFunction &IGF, Address container, + unsigned index) const { + assert(index < getNumStoredProtocols()); + return IGF.Builder.CreateStructGEP(container, index + 1, + (index + 1) * IGF.IGM.getPointerSize()); + } + + Address projectValue(IRGenFunction &IGF, Address existential) const { + return IGF.Builder.CreateStructGEP(existential, 0, Size(0), + existential.getAddress()->getName() + + asDerived().getStructNameSuffix()); + } + + void assignWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T, + bool isOutlined) const override { + if (isOutlined) { + Address destValue = projectValue(IGF, dest); + Address srcValue = projectValue(IGF, src); + asDerived().emitValueAssignWithCopy(IGF, destValue, srcValue); + emitCopyOfTables(IGF, dest, src); + } else { + OutliningMetadataCollector collector(IGF); + collector.emitCallToOutlinedCopy(dest, src, T, *this, + IsNotInitialization, IsNotTake); + } + } + + void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src, + SILType T, bool isOutlined) const override { + if (isOutlined) { + Address destValue = projectValue(IGF, dest); + Address srcValue = projectValue(IGF, src); + asDerived().emitValueInitializeWithCopy(IGF, destValue, srcValue); + emitCopyOfTables(IGF, dest, src); + } else { + OutliningMetadataCollector collector(IGF); + collector.emitCallToOutlinedCopy(dest, src, T, *this, + IsInitialization, IsNotTake); + } + } + + void assignWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T, + bool isOutlined) const override { + if (isOutlined) { + Address destValue = projectValue(IGF, dest); + Address srcValue = projectValue(IGF, src); + asDerived().emitValueAssignWithTake(IGF, destValue, srcValue); + emitCopyOfTables(IGF, dest, src); + } else { + OutliningMetadataCollector collector(IGF); + collector.emitCallToOutlinedCopy(dest, src, T, *this, + IsNotInitialization, IsTake); + } + } + + void initializeWithTake(IRGenFunction &IGF, Address dest, Address src, + SILType T, bool isOutlined) const override { + if (isOutlined) { + Address destValue = projectValue(IGF, dest); + Address srcValue = projectValue(IGF, src); + asDerived().emitValueInitializeWithTake(IGF, destValue, srcValue); + emitCopyOfTables(IGF, dest, src); + } else { + OutliningMetadataCollector collector(IGF); + collector.emitCallToOutlinedCopy(dest, src, T, *this, + IsInitialization, IsTake); + } + } + + void destroy(IRGenFunction &IGF, Address existential, SILType T, + bool isOutlined) const override { + if (isOutlined) { + Address valueAddr = projectValue(IGF, existential); + asDerived().emitValueDestroy(IGF, valueAddr); + } else { + OutliningMetadataCollector collector(IGF); + collector.emitCallToOutlinedDestroy(existential, T, *this); + } + } + }; + + /// A helper class for working with existential types that can be + /// exploded into scalars. + /// + /// The subclass must provide: + /// void emitValueRetain(IRGenFunction &IGF, llvm::Value *value) const; + /// void emitValueRelease(IRGenFunction &IGF, llvm::Value *value) const; + /// void emitValueFixLifetime(IRGenFunction &IGF, + /// llvm::Value *value) const; + /// const LoadableTypeInfo & + /// getValueTypeInfoForExtraInhabitants(IRGenModule &IGM) const; + /// The value type info is only used to manage extra inhabitants, so it's + /// okay for it to implement different semantics. + template + class ScalarExistentialTypeInfoBase : + public ExistentialTypeInfoBase> { + + using super = + ExistentialTypeInfoBase>; + + protected: + template + ScalarExistentialTypeInfoBase(T &&...args) + : super(std::forward(args)...) {} + + using super::asDerived; + + public: + /// The storage type of a class existential is a struct containing + /// a refcounted pointer to the class instance value followed by + /// witness table pointers for each conformed-to protocol. Unlike opaque + /// existentials, a class existential does not need to store type + /// metadata as an additional element, since it can be derived from the + /// class instance. + llvm::StructType *getStorageType() const { + return cast(TypeInfo::getStorageType()); + } + + using super::getNumStoredProtocols; + + unsigned getExplosionSize() const final { + return 1 + getNumStoredProtocols(); + } + + void getSchema(ExplosionSchema &schema) const override { + schema.add(ExplosionSchema::Element::forScalar(asDerived().getValueType())); + + llvm::StructType *ty = getStorageType(); + for (unsigned i = 1, e = getExplosionSize(); i != e; ++i) + schema.add(ExplosionSchema::Element::forScalar(ty->getElementType(i))); + } + + void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering, + Size offset) const override { + auto ptrSize = IGM.getPointerSize(); + LoadableTypeInfo::addScalarToAggLowering(IGM, lowering, + asDerived().getValueType(), + offset, ptrSize); + + llvm::StructType *ty = getStorageType(); + for (unsigned i = 1, e = getExplosionSize(); i != e; ++i) + LoadableTypeInfo::addScalarToAggLowering(IGM, lowering, + ty->getElementType(i), + offset + i * ptrSize, ptrSize); + } + + /// Given the address of a class existential container, returns + /// the address of a witness table pointer. + Address projectWitnessTable(IRGenFunction &IGF, Address address, + unsigned n) const { + assert(n < getNumStoredProtocols() && "witness table index out of bounds"); + return IGF.Builder.CreateStructGEP(address, n+1, + IGF.IGM.getPointerSize() * (n+1)); + } + + /// Return the type of the instance value. + llvm::Type *getValueType() const { + return getStorageType()->getElementType(0); + } + + /// Given the address of a class existential container, returns + /// the address of its instance pointer. + Address projectValue(IRGenFunction &IGF, Address address) const { + return IGF.Builder.CreateStructGEP(address, 0, Size(0)); + } + + llvm::Value *loadValue(IRGenFunction &IGF, Address addr) const { + return IGF.Builder.CreateLoad(asDerived().projectValue(IGF, addr)); + } + + /// Given a class existential container, returns a witness table + /// pointer out of the container, and the type metadata pointer for the + /// value. + llvm::Value * + extractWitnessTable(IRGenFunction &IGF, Explosion &container, + unsigned which) const { + assert(which < getNumStoredProtocols() && "witness table index out of bounds"); + ArrayRef values = container.claim(getExplosionSize()); + return values[which+1]; + } + + /// Deconstruct an existential object into witness tables and instance + /// pointer. + std::pair, llvm::Value*> + getWitnessTablesAndValue(Explosion &container) const { + llvm::Value *instance = container.claimNext(); + ArrayRef witnesses = container.claim(getNumStoredProtocols()); + return {witnesses, instance}; + } + + /// Given an existential object, returns the payload value. + llvm::Value *getValue(IRGenFunction &IGF, Explosion &container) const { + llvm::Value *instance = container.claimNext(); + (void)container.claim(getNumStoredProtocols()); + return instance; + } + + void loadAsCopy(IRGenFunction &IGF, Address address, + Explosion &out) const override { + // Load the instance pointer, which is unknown-refcounted. + llvm::Value *instance = asDerived().loadValue(IGF, address); + asDerived().emitValueRetain(IGF, instance, IGF.getDefaultAtomicity()); + out.add(instance); + + // Load the witness table pointers. + asDerived().emitLoadOfTables(IGF, address, out); + } + + void loadAsTake(IRGenFunction &IGF, Address address, + Explosion &e) const override { + // Load the instance pointer. + e.add(asDerived().loadValue(IGF, address)); + + // Load the witness table pointers. + asDerived().emitLoadOfTables(IGF, address, e); + } + + void assign(IRGenFunction &IGF, Explosion &e, Address address, + bool isOutlined) const override { + // Assign the value. + Address instanceAddr = asDerived().projectValue(IGF, address); + llvm::Value *old = IGF.Builder.CreateLoad(instanceAddr); + IGF.Builder.CreateStore(e.claimNext(), instanceAddr); + asDerived().emitValueRelease(IGF, old, IGF.getDefaultAtomicity()); + + // Store the witness table pointers. + asDerived().emitStoreOfTables(IGF, e, address); + } + + void initialize(IRGenFunction &IGF, Explosion &e, Address address, + bool isOutlined) const override { + // Store the instance pointer. + IGF.Builder.CreateStore(e.claimNext(), + asDerived().projectValue(IGF, address)); + + // Store the witness table pointers. + asDerived().emitStoreOfTables(IGF, e, address); + } + + void copy(IRGenFunction &IGF, Explosion &src, Explosion &dest, + Atomicity atomicity) + const override { + // Copy the instance pointer. + llvm::Value *value = src.claimNext(); + dest.add(value); + asDerived().emitValueRetain(IGF, value, atomicity); + + // Transfer the witness table pointers. + src.transferInto(dest, getNumStoredProtocols()); + } + + void consume(IRGenFunction &IGF, Explosion &src, Atomicity atomicity) + const override { + // Copy the instance pointer. + llvm::Value *value = src.claimNext(); + asDerived().emitValueRelease(IGF, value, atomicity); + + // Throw out the witness table pointers. + (void)src.claim(getNumStoredProtocols()); + } + + void fixLifetime(IRGenFunction &IGF, Explosion &src) const override { + // Copy the instance pointer. + llvm::Value *value = src.claimNext(); + asDerived().emitValueFixLifetime(IGF, value); + + // Throw out the witness table pointers. + (void)src.claim(getNumStoredProtocols()); + } + + void destroy(IRGenFunction &IGF, Address addr, SILType T, + bool isOutlined) const override { + // Small type (scalar) do not create outlined function + llvm::Value *value = asDerived().loadValue(IGF, addr); + asDerived().emitValueRelease(IGF, value, IGF.getDefaultAtomicity()); + } + + void packIntoEnumPayload(IRGenFunction &IGF, + EnumPayload &payload, + Explosion &src, + unsigned offset) const override { + payload.insertValue(IGF, src.claimNext(), offset); + auto wordSize = IGF.IGM.getPointerSize().getValueInBits(); + for (unsigned i = 0; i < getNumStoredProtocols(); ++i) { + offset += wordSize; + payload.insertValue(IGF, src.claimNext(), offset); + } + } + + void unpackFromEnumPayload(IRGenFunction &IGF, + const EnumPayload &payload, + Explosion &dest, + unsigned offset) const override { + ExplosionSchema schema; + getSchema(schema); + dest.add(payload.extractValue(IGF, schema[0].getScalarType(), offset)); + auto wordSize = IGF.IGM.getPointerSize().getValueInBits(); + for (unsigned i = 0; i < getNumStoredProtocols(); ++i) { + offset += wordSize; + dest.add(payload.extractValue(IGF, IGF.IGM.WitnessTablePtrTy, offset)); + } + } + + + // Extra inhabitants of the various scalar existential containers. + // We use the heap object extra inhabitants over the class pointer value. + // We could get even more extra inhabitants from the witness table + // pointer(s), but it's unlikely we would ever need to. + + bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { + assert(asDerived().getValueTypeInfoForExtraInhabitants(IGM) + .mayHaveExtraInhabitants(IGM)); + return true; + } + + unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { + return asDerived().getValueTypeInfoForExtraInhabitants(IGM) + .getFixedExtraInhabitantCount(IGM); + } + + APInt getFixedExtraInhabitantValue(IRGenModule &IGM, + unsigned bits, + unsigned index) const override { + // Note that we pass down the original bit-width. + return asDerived().getValueTypeInfoForExtraInhabitants(IGM) + .getFixedExtraInhabitantValue(IGM, bits, index); + } + + llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, + SILType T) + const override { + // NB: We assume that the witness table slots are zero if an extra + // inhabitant is stored in the container. + src = projectValue(IGF, src); + return asDerived().getValueTypeInfoForExtraInhabitants(IGF.IGM) + .getExtraInhabitantIndex(IGF, src, SILType()); + } + + void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, + Address dest, SILType T) const override { + Address valueDest = projectValue(IGF, dest); + asDerived().getValueTypeInfoForExtraInhabitants(IGF.IGM) + .storeExtraInhabitant(IGF, index, valueDest, SILType()); + } + + APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override { + // Ask the value type for its mask. + APInt bits = asDerived().getValueTypeInfoForExtraInhabitants(IGM) + .getFixedExtraInhabitantMask(IGM); + + // Zext out to the size of the existential. + bits = bits.zextOrTrunc(asDerived().getFixedSize().getValueInBits()); + return bits; + } + }; + +/// A type implementation for existential types. +#define LOADABLE_REF_STORAGE_HELPER(Name) \ + private: \ + bool shouldStoreExtraInhabitantsInRef(IRGenModule &IGM) const { \ + if (getNumStoredProtocols() == 0) \ + return true; \ + return IGM.getReferenceStorageExtraInhabitantCount( \ + ReferenceOwnership::Name, Refcounting) > 1; \ + } \ + public: \ + bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { \ + return getFixedExtraInhabitantCount(IGM) > 0; \ + } \ + unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { \ + if (shouldStoreExtraInhabitantsInRef(IGM)) { \ + return IGM.getReferenceStorageExtraInhabitantCount( \ + ReferenceOwnership::Name, Refcounting) - IsOptional; \ + } else { \ + return LoadableTypeInfo::getFixedExtraInhabitantCount(IGM); \ + } \ + } \ + APInt getFixedExtraInhabitantValue(IRGenModule &IGM, \ + unsigned bits, \ + unsigned index) const override { \ + if (shouldStoreExtraInhabitantsInRef(IGM)) { \ + return IGM.getReferenceStorageExtraInhabitantValue(bits, \ + index + IsOptional, \ + ReferenceOwnership::Name, \ + Refcounting); \ + } else { \ + return LoadableTypeInfo::getFixedExtraInhabitantValue(IGM, \ + bits, index); \ + } \ + } \ + llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, \ + SILType T) const override { \ + Address valueSrc = projectValue(IGF, src); \ + if (shouldStoreExtraInhabitantsInRef(IGF.IGM)) { \ + return IGF.getReferenceStorageExtraInhabitantIndex(valueSrc, \ + ReferenceOwnership::Name, Refcounting); \ + } else { \ + return LoadableTypeInfo::getExtraInhabitantIndex(IGF, src, T); \ + } \ + } \ + void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, \ + Address dest, SILType T) const override { \ + Address valueDest = projectValue(IGF, dest); \ + if (shouldStoreExtraInhabitantsInRef(IGF.IGM)) { \ + return IGF.storeReferenceStorageExtraInhabitant(index, valueDest, \ + ReferenceOwnership::Name, Refcounting); \ + } else { \ + return LoadableTypeInfo::storeExtraInhabitant(IGF, index, dest, T); \ + } \ + } \ + APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override { \ + if (shouldStoreExtraInhabitantsInRef(IGM)) { \ + APInt bits = IGM.getReferenceStorageExtraInhabitantMask( \ + ReferenceOwnership::Name, \ + Refcounting); \ + /* Zext out to the size of the existential. */ \ + bits = bits.zextOrTrunc(getFixedSize().getValueInBits()); \ + return bits; \ + } else { \ + return LoadableTypeInfo::getFixedExtraInhabitantMask(IGM); \ + } \ + } +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + class AddressOnly##Name##ClassExistentialTypeInfo final : \ + public AddressOnlyClassExistentialTypeInfoBase< \ + AddressOnly##Name##ClassExistentialTypeInfo, \ + FixedTypeInfo> { \ + public: \ + AddressOnly##Name##ClassExistentialTypeInfo( \ + ArrayRef protocols, \ + llvm::Type *ty, \ + SpareBitVector &&spareBits, \ + Size size, Alignment align, \ + ReferenceCounting refcounting, \ + bool isOptional) \ + : AddressOnlyClassExistentialTypeInfoBase(protocols, refcounting, \ + ty, size, std::move(spareBits), \ + align, IsNotPOD, \ + IsNotBitwiseTakable, \ + IsFixedSize) {} \ + void emitValueAssignWithCopy(IRGenFunction &IGF, \ + Address dest, Address src) const { \ + IGF.emit##Name##CopyAssign(dest, src, Refcounting); \ + } \ + void emitValueInitializeWithCopy(IRGenFunction &IGF, \ + Address dest, Address src) const { \ + IGF.emit##Name##CopyInit(dest, src, Refcounting); \ + } \ + void emitValueAssignWithTake(IRGenFunction &IGF, \ + Address dest, Address src) const { \ + IGF.emit##Name##TakeAssign(dest, src, Refcounting); \ + } \ + void emitValueInitializeWithTake(IRGenFunction &IGF, \ + Address dest, Address src) const { \ + IGF.emit##Name##TakeInit(dest, src, Refcounting); \ + } \ + void emitValueDestroy(IRGenFunction &IGF, Address addr) const { \ + IGF.emit##Name##Destroy(addr, Refcounting); \ + } \ + StringRef getStructNameSuffix() const { return "." #name "ref"; } \ + }; +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + class Loadable##Name##ClassExistentialTypeInfo final \ + : public ScalarExistentialTypeInfoBase< \ + Loadable##Name##ClassExistentialTypeInfo, \ + LoadableTypeInfo> { \ + ReferenceCounting Refcounting; \ + llvm::Type *ValueType; \ + bool IsOptional; \ + public: \ + Loadable##Name##ClassExistentialTypeInfo( \ + ArrayRef storedProtocols, \ + llvm::Type *valueTy, \ + llvm::Type *ty, \ + const SpareBitVector &spareBits, \ + Size size, Alignment align, \ + ReferenceCounting refcounting, \ + bool isOptional) \ + : ScalarExistentialTypeInfoBase(storedProtocols, ty, size, \ + spareBits, align, IsNotPOD, IsFixedSize), \ + Refcounting(refcounting), ValueType(valueTy), IsOptional(isOptional) { \ + assert(refcounting == ReferenceCounting::Native || \ + refcounting == ReferenceCounting::Unknown); \ + } \ + llvm::Type *getValueType() const { \ + return ValueType; \ + } \ + Address projectValue(IRGenFunction &IGF, Address addr) const { \ + Address valueAddr = ScalarExistentialTypeInfoBase::projectValue(IGF, addr); \ + return IGF.Builder.CreateBitCast(valueAddr, ValueType->getPointerTo()); \ + } \ + void emitValueRetain(IRGenFunction &IGF, llvm::Value *value, \ + Atomicity atomicity) const { \ + IGF.emit##Name##Retain(value, Refcounting, atomicity); \ + } \ + void emitValueRelease(IRGenFunction &IGF, llvm::Value *value, \ + Atomicity atomicity) const { \ + IGF.emit##Name##Release(value, Refcounting, atomicity); \ + } \ + void emitValueFixLifetime(IRGenFunction &IGF, llvm::Value *value) const { \ + IGF.emitFixLifetime(value); \ + } \ + const LoadableTypeInfo & \ + getValueTypeInfoForExtraInhabitants(IRGenModule &IGM) const { \ + llvm_unreachable("should have overridden all actual uses of this"); \ + } \ + LOADABLE_REF_STORAGE_HELPER(Name) \ + }; +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...") + +/// A type implementation for static reference storage class existential types +/// that do not generate dynamic (i.e. runtime) logic. +#define UNCHECKED_REF_STORAGE(Name, ...) \ + class Name##ClassExistentialTypeInfo final \ + : public ScalarExistentialTypeInfoBase { \ + public: \ + Name##ClassExistentialTypeInfo(ArrayRef storedProtocols, \ + llvm::Type *ty, \ + const SpareBitVector &spareBits, \ + Size size, Alignment align, \ + bool isOptional) \ + : ScalarExistentialTypeInfoBase(storedProtocols, ty, size, \ + spareBits, align, IsPOD, IsFixedSize) {} \ + const LoadableTypeInfo & \ + getValueTypeInfoForExtraInhabitants(IRGenModule &IGM) const { \ + if (!IGM.ObjCInterop) \ + return IGM.getNativeObjectTypeInfo(); \ + else \ + return IGM.getUnknownObjectTypeInfo(); \ + } \ + /* FIXME -- Use LOADABLE_REF_STORAGE_HELPER and make */ \ + /* getValueTypeInfoForExtraInhabitantsThis call llvm_unreachable() */ \ + void emitValueRetain(IRGenFunction &IGF, llvm::Value *value, \ + Atomicity atomicity) const {} \ + void emitValueRelease(IRGenFunction &IGF, llvm::Value *value, \ + Atomicity atomicity) const {} \ + void emitValueFixLifetime(IRGenFunction &IGF, llvm::Value *value) const {} \ + }; +#include "swift/AST/ReferenceStorage.def" +#undef LOADABLE_REF_STORAGE_HELPER } // end anonymous namespace @@ -135,126 +822,6 @@ getProjectBoxedOpaqueExistentialFunction(IRGenFunction &IGF, namespace { -/// A helper class for implementing existential type infos that -/// store an existential value of some sort. -template -class ExistentialTypeInfoBase : public Base, - private llvm::TrailingObjects { - friend class llvm::TrailingObjects; - - /// The number of non-trivial protocols for this existential. - unsigned NumStoredProtocols; - -protected: - const Derived &asDerived() const { - return *static_cast(this); - } - Derived &asDerived() { - return *static_cast(this); - } - - template - ExistentialTypeInfoBase(ArrayRef protocols, - As &&...args) - : Base(std::forward(args)...), - NumStoredProtocols(protocols.size()) { - std::uninitialized_copy(protocols.begin(), protocols.end(), - this->template getTrailingObjects()); - } - -public: - template - static const Derived * - create(ArrayRef protocols, As &&...args) - { - void *buffer = - operator new(ExistentialTypeInfoBase::template totalSizeToAlloc(protocols.size())); - return new (buffer) Derived(protocols, std::forward(args)...); - } - - /// Returns the number of protocol witness tables directly carried - /// by values of this type. - unsigned getNumStoredProtocols() const { return NumStoredProtocols; } - - /// Returns the protocols that values of this type are known to - /// implement. This can be empty, meaning that values of this - /// type are not know to implement any protocols, although we do - /// still know how to manipulate them. - ArrayRef getStoredProtocols() const { - return {this->template getTrailingObjects(), - NumStoredProtocols}; - } - - /// Given an existential object, find the witness table - /// corresponding to the given protocol. - llvm::Value *findWitnessTable(IRGenFunction &IGF, - Explosion &container, - ProtocolDecl *protocol) const { - assert(NumStoredProtocols != 0 && - "finding a witness table in a trivial existential"); - - return emitImpliedWitnessTableRef(IGF, getStoredProtocols(), protocol, - [&](unsigned originIndex) { - return asDerived().extractWitnessTable(IGF, container, originIndex); - }); - } - - /// Given the address of an existential object, find the witness - /// table corresponding to the given protocol. - llvm::Value *findWitnessTable(IRGenFunction &IGF, Address obj, - ProtocolDecl *protocol) const { - assert(NumStoredProtocols != 0 && - "finding a witness table in a trivial existential"); - - return emitImpliedWitnessTableRef(IGF, getStoredProtocols(), protocol, - [&](unsigned originIndex) { - return asDerived().loadWitnessTable(IGF, obj, originIndex); - }); - } - - /// Given the witness table vector from an existential object, find the - /// witness table corresponding to the given protocol. - llvm::Value *findWitnessTable(IRGenFunction &IGF, - ArrayRef witnesses, - ProtocolDecl *protocol) const { - return emitImpliedWitnessTableRef(IGF, getStoredProtocols(), protocol, - [&](unsigned originIndex) { - return witnesses[originIndex]; - }); - } - - /// Given the address of an existential object, find the witness - /// table of a directly-stored witness table. - llvm::Value *loadWitnessTable(IRGenFunction &IGF, Address obj, - unsigned which) const { - return IGF.Builder.CreateLoad( - asDerived().projectWitnessTable(IGF, obj, which)); - } - - void emitCopyOfTables(IRGenFunction &IGF, Address dest, Address src) const { - if (NumStoredProtocols == 0) return; - - Explosion temp; - asDerived().emitLoadOfTables(IGF, src, temp); - asDerived().emitStoreOfTables(IGF, temp, dest); - } - - void emitLoadOfTables(IRGenFunction &IGF, Address existential, - Explosion &out) const { - for (unsigned i = 0; i != NumStoredProtocols; ++i) { - auto tableAddr = asDerived().projectWitnessTable(IGF, existential, i); - out.add(IGF.Builder.CreateLoad(tableAddr)); - } - } - - void emitStoreOfTables(IRGenFunction &IGF, Explosion &in, - Address existential) const { - for (unsigned i = 0; i != NumStoredProtocols; ++i) { - auto tableAddr = asDerived().projectWitnessTable(IGF, existential, i); - IGF.Builder.CreateStore(in.claimNext(), tableAddr); - } - } -}; /// A TypeInfo implementation for existential types, i.e., types like: /// Printable @@ -368,106 +935,30 @@ public: } }; -/// A type implementation for address-only reference storage of -/// class existential types. -template -class AddressOnlyClassExistentialTypeInfoBase : - public ExistentialTypeInfoBase> { - using super = ExistentialTypeInfoBase>; - using super::asDerived; - using super::emitCopyOfTables; - using super::getNumStoredProtocols; - -protected: - const ReferenceCounting Refcounting; - - template - AddressOnlyClassExistentialTypeInfoBase(ArrayRef protocols, - ReferenceCounting refcounting, - As &&...args) - : super(protocols, std::forward(args)...), +/// A type info implementation for class existential types, that is, +/// an existential type known to conform to one or more class protocols. +/// Class existentials can be represented directly as an aggregation +/// of a refcounted pointer plus witness tables instead of using an indirect +/// buffer. +class ClassExistentialTypeInfo final + : public ScalarExistentialTypeInfoBase { + ReferenceCounting Refcounting; + + friend ExistentialTypeInfoBase; + ClassExistentialTypeInfo(ArrayRef protocols, + llvm::Type *ty, + Size size, + SpareBitVector &&spareBits, + Alignment align, + ReferenceCounting refcounting) + : ScalarExistentialTypeInfoBase(protocols, ty, size, + std::move(spareBits), align), Refcounting(refcounting) { - } - -public: - Address projectWitnessTable(IRGenFunction &IGF, Address container, - unsigned index) const { - assert(index < getNumStoredProtocols()); - return IGF.Builder.CreateStructGEP(container, index + 1, - (index + 1) * IGF.IGM.getPointerSize()); - } - - Address projectValue(IRGenFunction &IGF, Address existential) const { - return IGF.Builder.CreateStructGEP(existential, 0, Size(0), - existential.getAddress()->getName() + ".weakref"); - } - - void assignWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T, - bool isOutlined) const override { - if (isOutlined) { - Address destValue = projectValue(IGF, dest); - Address srcValue = projectValue(IGF, src); - asDerived().emitValueAssignWithCopy(IGF, destValue, srcValue); - emitCopyOfTables(IGF, dest, src); - } else { - OutliningMetadataCollector collector(IGF); - collector.emitCallToOutlinedCopy(dest, src, T, *this, - IsNotInitialization, IsNotTake); - } - } - - void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src, - SILType T, bool isOutlined) const override { - if (isOutlined) { - Address destValue = projectValue(IGF, dest); - Address srcValue = projectValue(IGF, src); - asDerived().emitValueInitializeWithCopy(IGF, destValue, srcValue); - emitCopyOfTables(IGF, dest, src); - } else { - OutliningMetadataCollector collector(IGF); - collector.emitCallToOutlinedCopy(dest, src, T, *this, - IsInitialization, IsNotTake); - } - } - - void assignWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T, - bool isOutlined) const override { - if (isOutlined) { - Address destValue = projectValue(IGF, dest); - Address srcValue = projectValue(IGF, src); - asDerived().emitValueAssignWithTake(IGF, destValue, srcValue); - emitCopyOfTables(IGF, dest, src); - } else { - OutliningMetadataCollector collector(IGF); - collector.emitCallToOutlinedCopy(dest, src, T, *this, - IsNotInitialization, IsTake); - } - } - - void initializeWithTake(IRGenFunction &IGF, Address dest, Address src, - SILType T, bool isOutlined) const override { - if (isOutlined) { - Address destValue = projectValue(IGF, dest); - Address srcValue = projectValue(IGF, src); - asDerived().emitValueInitializeWithTake(IGF, destValue, srcValue); - emitCopyOfTables(IGF, dest, src); - } else { - OutliningMetadataCollector collector(IGF); - collector.emitCallToOutlinedCopy(dest, src, T, *this, - IsInitialization, IsTake); - } - } - - void destroy(IRGenFunction &IGF, Address existential, SILType T, - bool isOutlined) const override { - if (isOutlined) { - Address valueAddr = projectValue(IGF, existential); - asDerived().emitValueDestroy(IGF, valueAddr); - } else { - OutliningMetadataCollector collector(IGF); - collector.emitCallToOutlinedDestroy(existential, T, *this); - } + assert(refcounting == ReferenceCounting::Native || + refcounting == ReferenceCounting::Unknown || + refcounting == ReferenceCounting::ObjC); } /// Given an explosion with multiple pointer elements in them, pack them @@ -507,592 +998,6 @@ public: IGF.IGM.WitnessTablePtrTy)); } } -}; - -/// A type implementation for 'weak' existential types. -class WeakClassExistentialTypeInfo final : - public AddressOnlyClassExistentialTypeInfoBase { -public: - WeakClassExistentialTypeInfo(ArrayRef protocols, - llvm::Type *ty, Size size, Alignment align, - SpareBitVector &&spareBits, - ReferenceCounting refcounting) - : AddressOnlyClassExistentialTypeInfoBase(protocols, refcounting, - ty, size, align, - std::move(spareBits)) { - } - - void emitValueAssignWithCopy(IRGenFunction &IGF, - Address dest, Address src) const { - IGF.emitWeakCopyAssign(dest, src, Refcounting); - } - - void emitValueInitializeWithCopy(IRGenFunction &IGF, - Address dest, Address src) const { - IGF.emitWeakCopyInit(dest, src, Refcounting); - } - - void emitValueAssignWithTake(IRGenFunction &IGF, - Address dest, Address src) const { - IGF.emitWeakTakeAssign(dest, src, Refcounting); - } - - void emitValueInitializeWithTake(IRGenFunction &IGF, - Address dest, Address src) const { - IGF.emitWeakTakeInit(dest, src, Refcounting); - } - - void emitValueDestroy(IRGenFunction &IGF, Address addr) const { - IGF.emitWeakDestroy(addr, Refcounting); - } - - // These explosions must follow the same schema as - // ClassExistentialTypeInfo, i.e. first the value, then the tables. - - void weakLoadStrong(IRGenFunction &IGF, Address existential, - Explosion &out) const override { - Explosion temp; - Address valueAddr = projectValue(IGF, existential); - llvm::Type *resultType = IGF.IGM.getReferenceType(Refcounting); - temp.add(IGF.emitWeakLoadStrong(valueAddr, resultType, Refcounting)); - emitLoadOfTables(IGF, existential, temp); - mergeExplosion(temp, out, IGF); - } - - void weakTakeStrong(IRGenFunction &IGF, Address existential, - Explosion &out) const override { - Explosion temp; - Address valueAddr = projectValue(IGF, existential); - llvm::Type *resultType = IGF.IGM.getReferenceType(Refcounting); - temp.add(IGF.emitWeakTakeStrong(valueAddr, resultType, Refcounting)); - emitLoadOfTables(IGF, existential, temp); - mergeExplosion(temp, out, IGF); - } - - void weakInit(IRGenFunction &IGF, Explosion &in, - Address existential) const override { - Explosion temp; - decomposeExplosion(in, temp, IGF); - - llvm::Value *value = temp.claimNext(); - assert(value->getType() == IGF.IGM.getReferenceType(Refcounting)); - emitStoreOfTables(IGF, temp, existential); - Address valueAddr = projectValue(IGF, existential); - IGF.emitWeakInit(value, valueAddr, Refcounting); - } - - void weakAssign(IRGenFunction &IGF, Explosion &in, - Address existential) const override { - Explosion temp; - decomposeExplosion(in, temp, IGF); - - llvm::Value *value = temp.claimNext(); - assert(value->getType() == IGF.IGM.getReferenceType(Refcounting)); - emitStoreOfTables(IGF, temp, existential); - Address valueAddr = projectValue(IGF, existential); - IGF.emitWeakAssign(value, valueAddr, Refcounting); - } -}; - -/// A type implementation for address-only @unowned existential types. -class AddressOnlyUnownedClassExistentialTypeInfo final : - public AddressOnlyClassExistentialTypeInfoBase< - AddressOnlyUnownedClassExistentialTypeInfo, - FixedTypeInfo> { -public: - AddressOnlyUnownedClassExistentialTypeInfo(ArrayRef protocols, - llvm::Type *ty, - SpareBitVector &&spareBits, - Size size, Alignment align, - ReferenceCounting refcounting) - : AddressOnlyClassExistentialTypeInfoBase(protocols, refcounting, - ty, size, std::move(spareBits), - align, IsNotPOD, - IsNotBitwiseTakable, - IsFixedSize) { - } - - void emitValueAssignWithCopy(IRGenFunction &IGF, - Address dest, Address src) const { - IGF.emitUnownedCopyAssign(dest, src, Refcounting); - } - - void emitValueInitializeWithCopy(IRGenFunction &IGF, - Address dest, Address src) const { - IGF.emitUnownedCopyInit(dest, src, Refcounting); - } - - void emitValueAssignWithTake(IRGenFunction &IGF, - Address dest, Address src) const { - IGF.emitUnownedTakeAssign(dest, src, Refcounting); - } - - void emitValueInitializeWithTake(IRGenFunction &IGF, - Address dest, Address src) const { - IGF.emitUnownedTakeInit(dest, src, Refcounting); - } - - void emitValueDestroy(IRGenFunction &IGF, Address addr) const { - IGF.emitUnownedDestroy(addr, Refcounting); - } - - bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { - return true; - } - - unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { - return IGM.getUnownedExtraInhabitantCount(Refcounting); - } - - APInt getFixedExtraInhabitantValue(IRGenModule &IGM, - unsigned bits, - unsigned index) const override { - return IGM.getUnownedExtraInhabitantValue(bits, index, Refcounting); - } - - llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, - SILType T) const override { - Address valueSrc = projectValue(IGF, src); - return IGF.getUnownedExtraInhabitantIndex(valueSrc, Refcounting); - } - - void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, - Address dest, SILType T) const override { - Address valueDest = projectValue(IGF, dest); - return IGF.storeUnownedExtraInhabitant(index, valueDest, Refcounting); - } - - APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override { - APInt bits = IGM.getUnownedExtraInhabitantMask(Refcounting); - - // Zext out to the size of the existential. - bits = bits.zextOrTrunc(getFixedSize().getValueInBits()); - return bits; - } -}; - -/// A helper class for working with existential types that can be -/// exploded into scalars. -/// -/// The subclass must provide: -/// void emitValueRetain(IRGenFunction &IGF, llvm::Value *value) const; -/// void emitValueRelease(IRGenFunction &IGF, llvm::Value *value) const; -/// void emitValueFixLifetime(IRGenFunction &IGF, -/// llvm::Value *value) const; -/// const LoadableTypeInfo & -/// getValueTypeInfoForExtraInhabitants(IRGenModule &IGM) const; -/// The value type info is only used to manage extra inhabitants, so it's -/// okay for it to implement different semantics. -template -class ScalarExistentialTypeInfoBase : - public ExistentialTypeInfoBase> { - - using super = - ExistentialTypeInfoBase>; - -protected: - template - ScalarExistentialTypeInfoBase(T &&...args) - : super(std::forward(args)...) {} - - using super::asDerived; - -public: - /// The storage type of a class existential is a struct containing - /// a refcounted pointer to the class instance value followed by - /// witness table pointers for each conformed-to protocol. Unlike opaque - /// existentials, a class existential does not need to store type - /// metadata as an additional element, since it can be derived from the - /// class instance. - llvm::StructType *getStorageType() const { - return cast(TypeInfo::getStorageType()); - } - - using super::getNumStoredProtocols; - - unsigned getExplosionSize() const final { - return 1 + getNumStoredProtocols(); - } - - void getSchema(ExplosionSchema &schema) const override { - schema.add(ExplosionSchema::Element::forScalar(asDerived().getValueType())); - - llvm::StructType *ty = getStorageType(); - for (unsigned i = 1, e = getExplosionSize(); i != e; ++i) - schema.add(ExplosionSchema::Element::forScalar(ty->getElementType(i))); - } - - void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering, - Size offset) const override { - auto ptrSize = IGM.getPointerSize(); - LoadableTypeInfo::addScalarToAggLowering(IGM, lowering, - asDerived().getValueType(), - offset, ptrSize); - - llvm::StructType *ty = getStorageType(); - for (unsigned i = 1, e = getExplosionSize(); i != e; ++i) - LoadableTypeInfo::addScalarToAggLowering(IGM, lowering, - ty->getElementType(i), - offset + i * ptrSize, ptrSize); - } - - /// Given the address of a class existential container, returns - /// the address of a witness table pointer. - Address projectWitnessTable(IRGenFunction &IGF, Address address, - unsigned n) const { - assert(n < getNumStoredProtocols() && "witness table index out of bounds"); - return IGF.Builder.CreateStructGEP(address, n+1, - IGF.IGM.getPointerSize() * (n+1)); - } - - /// Return the type of the instance value. - llvm::Type *getValueType() const { - return getStorageType()->getElementType(0); - } - - /// Given the address of a class existential container, returns - /// the address of its instance pointer. - Address projectValue(IRGenFunction &IGF, Address address) const { - return IGF.Builder.CreateStructGEP(address, 0, Size(0)); - } - - llvm::Value *loadValue(IRGenFunction &IGF, Address addr) const { - return IGF.Builder.CreateLoad(asDerived().projectValue(IGF, addr)); - } - - /// Given a class existential container, returns a witness table - /// pointer out of the container, and the type metadata pointer for the - /// value. - llvm::Value * - extractWitnessTable(IRGenFunction &IGF, Explosion &container, - unsigned which) const { - assert(which < getNumStoredProtocols() && "witness table index out of bounds"); - ArrayRef values = container.claim(getExplosionSize()); - return values[which+1]; - } - - /// Deconstruct an existential object into witness tables and instance - /// pointer. - std::pair, llvm::Value*> - getWitnessTablesAndValue(Explosion &container) const { - llvm::Value *instance = container.claimNext(); - ArrayRef witnesses = container.claim(getNumStoredProtocols()); - return {witnesses, instance}; - } - - /// Given an existential object, returns the payload value. - llvm::Value *getValue(IRGenFunction &IGF, Explosion &container) const { - llvm::Value *instance = container.claimNext(); - (void)container.claim(getNumStoredProtocols()); - return instance; - } - - void loadAsCopy(IRGenFunction &IGF, Address address, - Explosion &out) const override { - // Load the instance pointer, which is unknown-refcounted. - llvm::Value *instance = asDerived().loadValue(IGF, address); - asDerived().emitValueRetain(IGF, instance, IGF.getDefaultAtomicity()); - out.add(instance); - - // Load the witness table pointers. - asDerived().emitLoadOfTables(IGF, address, out); - } - - void loadAsTake(IRGenFunction &IGF, Address address, - Explosion &e) const override { - // Load the instance pointer. - e.add(asDerived().loadValue(IGF, address)); - - // Load the witness table pointers. - asDerived().emitLoadOfTables(IGF, address, e); - } - - void assign(IRGenFunction &IGF, Explosion &e, Address address, - bool isOutlined) const override { - // Assign the value. - Address instanceAddr = asDerived().projectValue(IGF, address); - llvm::Value *old = IGF.Builder.CreateLoad(instanceAddr); - IGF.Builder.CreateStore(e.claimNext(), instanceAddr); - asDerived().emitValueRelease(IGF, old, IGF.getDefaultAtomicity()); - - // Store the witness table pointers. - asDerived().emitStoreOfTables(IGF, e, address); - } - - void initialize(IRGenFunction &IGF, Explosion &e, Address address, - bool isOutlined) const override { - // Store the instance pointer. - IGF.Builder.CreateStore(e.claimNext(), - asDerived().projectValue(IGF, address)); - - // Store the witness table pointers. - asDerived().emitStoreOfTables(IGF, e, address); - } - - void copy(IRGenFunction &IGF, Explosion &src, Explosion &dest, - Atomicity atomicity) - const override { - // Copy the instance pointer. - llvm::Value *value = src.claimNext(); - dest.add(value); - asDerived().emitValueRetain(IGF, value, atomicity); - - // Transfer the witness table pointers. - src.transferInto(dest, getNumStoredProtocols()); - } - - void consume(IRGenFunction &IGF, Explosion &src, Atomicity atomicity) - const override { - // Copy the instance pointer. - llvm::Value *value = src.claimNext(); - asDerived().emitValueRelease(IGF, value, atomicity); - - // Throw out the witness table pointers. - (void)src.claim(getNumStoredProtocols()); - } - - void fixLifetime(IRGenFunction &IGF, Explosion &src) const override { - // Copy the instance pointer. - llvm::Value *value = src.claimNext(); - asDerived().emitValueFixLifetime(IGF, value); - - // Throw out the witness table pointers. - (void)src.claim(getNumStoredProtocols()); - } - - void destroy(IRGenFunction &IGF, Address addr, SILType T, - bool isOutlined) const override { - // Small type (scalar) do not create outlined function - llvm::Value *value = asDerived().loadValue(IGF, addr); - asDerived().emitValueRelease(IGF, value, IGF.getDefaultAtomicity()); - } - - void packIntoEnumPayload(IRGenFunction &IGF, - EnumPayload &payload, - Explosion &src, - unsigned offset) const override { - payload.insertValue(IGF, src.claimNext(), offset); - auto wordSize = IGF.IGM.getPointerSize().getValueInBits(); - for (unsigned i = 0; i < getNumStoredProtocols(); ++i) { - offset += wordSize; - payload.insertValue(IGF, src.claimNext(), offset); - } - } - - void unpackFromEnumPayload(IRGenFunction &IGF, - const EnumPayload &payload, - Explosion &dest, - unsigned offset) const override { - ExplosionSchema schema; - getSchema(schema); - dest.add(payload.extractValue(IGF, schema[0].getScalarType(), offset)); - auto wordSize = IGF.IGM.getPointerSize().getValueInBits(); - for (unsigned i = 0; i < getNumStoredProtocols(); ++i) { - offset += wordSize; - dest.add(payload.extractValue(IGF, IGF.IGM.WitnessTablePtrTy, offset)); - } - } - - - // Extra inhabitants of the various scalar existential containers. - // We use the heap object extra inhabitants over the class pointer value. - // We could get even more extra inhabitants from the witness table - // pointer(s), but it's unlikely we would ever need to. - - bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { - assert(asDerived().getValueTypeInfoForExtraInhabitants(IGM) - .mayHaveExtraInhabitants(IGM)); - return true; - } - - unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { - return asDerived().getValueTypeInfoForExtraInhabitants(IGM) - .getFixedExtraInhabitantCount(IGM); - } - - APInt getFixedExtraInhabitantValue(IRGenModule &IGM, - unsigned bits, - unsigned index) const override { - // Note that we pass down the original bit-width. - return asDerived().getValueTypeInfoForExtraInhabitants(IGM) - .getFixedExtraInhabitantValue(IGM, bits, index); - } - - llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, - SILType T) - const override { - // NB: We assume that the witness table slots are zero if an extra - // inhabitant is stored in the container. - src = projectValue(IGF, src); - return asDerived().getValueTypeInfoForExtraInhabitants(IGF.IGM) - .getExtraInhabitantIndex(IGF, src, SILType()); - } - - void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, - Address dest, SILType T) const override { - Address valueDest = projectValue(IGF, dest); - asDerived().getValueTypeInfoForExtraInhabitants(IGF.IGM) - .storeExtraInhabitant(IGF, index, valueDest, SILType()); - } - - APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override { - // Ask the value type for its mask. - APInt bits = asDerived().getValueTypeInfoForExtraInhabitants(IGM) - .getFixedExtraInhabitantMask(IGM); - - // Zext out to the size of the existential. - bits = bits.zextOrTrunc(asDerived().getFixedSize().getValueInBits()); - return bits; - } -}; - -/// A type implementation for loadable [unowned] class existential types. -class LoadableUnownedClassExistentialTypeInfo final - : public ScalarExistentialTypeInfoBase< - LoadableUnownedClassExistentialTypeInfo, - LoadableTypeInfo> { - ReferenceCounting Refcounting; - llvm::Type *ValueType; - -public: - LoadableUnownedClassExistentialTypeInfo( - ArrayRef storedProtocols, - llvm::Type *valueTy, - llvm::Type *ty, - const SpareBitVector &spareBits, - Size size, Alignment align, - ReferenceCounting refcounting) - : ScalarExistentialTypeInfoBase(storedProtocols, ty, size, - spareBits, align, IsNotPOD, IsFixedSize), - Refcounting(refcounting), ValueType(valueTy) { - assert(refcounting == ReferenceCounting::Native || - refcounting == ReferenceCounting::Unknown); - } - - llvm::Type *getValueType() const { - return ValueType; - } - - Address projectValue(IRGenFunction &IGF, Address addr) const { - Address valueAddr = ScalarExistentialTypeInfoBase::projectValue(IGF, addr); - return IGF.Builder.CreateBitCast(valueAddr, ValueType->getPointerTo()); - } - - void emitValueRetain(IRGenFunction &IGF, llvm::Value *value, - Atomicity atomicity) const { - IGF.emitUnownedRetain(value, Refcounting, atomicity); - } - - void emitValueRelease(IRGenFunction &IGF, llvm::Value *value, - Atomicity atomicity) const { - IGF.emitUnownedRelease(value, Refcounting, atomicity); - } - - void emitValueFixLifetime(IRGenFunction &IGF, llvm::Value *value) const { - IGF.emitFixLifetime(value); - } - - const LoadableTypeInfo & - getValueTypeInfoForExtraInhabitants(IRGenModule &IGM) const { - llvm_unreachable("should have overridden all actual uses of this"); - } - - bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { - return true; - } - - unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { - return IGM.getUnownedExtraInhabitantCount(Refcounting); - } - - APInt getFixedExtraInhabitantValue(IRGenModule &IGM, - unsigned bits, - unsigned index) const override { - return IGM.getUnownedExtraInhabitantValue(bits, index, Refcounting); - } - - llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, - SILType T) const override { - Address valueSrc = projectValue(IGF, src); - return IGF.getUnownedExtraInhabitantIndex(valueSrc, Refcounting); - } - - void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, - Address dest, SILType T) const override { - Address valueDest = projectValue(IGF, dest); - return IGF.storeUnownedExtraInhabitant(index, valueDest, Refcounting); - } - - APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override { - APInt bits = IGM.getUnownedExtraInhabitantMask(Refcounting); - - // Zext out to the size of the existential. - bits = bits.zextOrTrunc(asDerived().getFixedSize().getValueInBits()); - return bits; - } -}; - -/// A type implementation for @unowned(unsafe) class existential types. -class UnmanagedClassExistentialTypeInfo final - : public ScalarExistentialTypeInfoBase { -public: - UnmanagedClassExistentialTypeInfo(ArrayRef storedProtocols, - llvm::Type *ty, - const SpareBitVector &spareBits, - Size size, Alignment align) - : ScalarExistentialTypeInfoBase(storedProtocols, ty, size, - spareBits, align, IsPOD, IsFixedSize) {} - - const LoadableTypeInfo & - getValueTypeInfoForExtraInhabitants(IRGenModule &IGM) const { - if (!IGM.ObjCInterop) - return IGM.getNativeObjectTypeInfo(); - else - return IGM.getUnknownObjectTypeInfo(); - } - - void emitValueRetain(IRGenFunction &IGF, llvm::Value *value, - Atomicity atomicity) const { - // do nothing - } - - void emitValueRelease(IRGenFunction &IGF, llvm::Value *value, - Atomicity atomicity) const { - // do nothing - } - - void emitValueFixLifetime(IRGenFunction &IGF, llvm::Value *value) const { - // do nothing - } -}; - -/// A type info implementation for class existential types, that is, -/// an existential type known to conform to one or more class protocols. -/// Class existentials can be represented directly as an aggregation -/// of a refcounted pointer plus witness tables instead of using an indirect -/// buffer. -class ClassExistentialTypeInfo final - : public ScalarExistentialTypeInfoBase -{ - ReferenceCounting Refcounting; - - friend ExistentialTypeInfoBase; - ClassExistentialTypeInfo(ArrayRef protocols, - llvm::Type *ty, - Size size, - SpareBitVector &&spareBits, - Alignment align, - ReferenceCounting refcounting) - : ScalarExistentialTypeInfoBase(protocols, ty, size, - std::move(spareBits), align), - Refcounting(refcounting) { - assert(refcounting == ReferenceCounting::Native || - refcounting == ReferenceCounting::Unknown || - refcounting == ReferenceCounting::ObjC); - } public: @@ -1128,65 +1033,189 @@ public: (void)e.claim(getNumStoredProtocols()); } - void strongRetainUnowned(IRGenFunction &IGF, Explosion &e, - Atomicity atomicity) const override { - IGF.emitStrongRetainUnowned(e.claimNext(), Refcounting, atomicity); - (void)e.claim(getNumStoredProtocols()); +// We can just re-use the reference storage types. +#define NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + void name##LoadStrong(IRGenFunction &IGF, Address existential, \ + Explosion &out, bool isOptional) const override { \ + if (isOptional) { \ + Explosion temp; \ + Address valueAddr = projectValue(IGF, existential); \ + llvm::Type *resultType = IGF.IGM.getReferenceType(Refcounting); \ + temp.add(IGF.emit##Name##LoadStrong(valueAddr, resultType, Refcounting));\ + emitLoadOfTables(IGF, existential, temp); \ + mergeExplosion(temp, out, IGF); \ + } else { \ + Address valueAddr = projectValue(IGF, existential); \ + out.add(IGF.emit##Name##LoadStrong(valueAddr, \ + getPayloadType(), \ + Refcounting)); \ + emitLoadOfTables(IGF, existential, out); \ + } \ + } \ + void name##TakeStrong(IRGenFunction &IGF, Address existential, \ + Explosion &out, bool isOptional) const override { \ + if (isOptional) { \ + Explosion temp; \ + Address valueAddr = projectValue(IGF, existential); \ + llvm::Type *resultType = IGF.IGM.getReferenceType(Refcounting); \ + temp.add(IGF.emit##Name##TakeStrong(valueAddr, resultType, Refcounting));\ + emitLoadOfTables(IGF, existential, temp); \ + mergeExplosion(temp, out, IGF); \ + } else { \ + Address valueAddr = projectValue(IGF, existential); \ + out.add(IGF.emit##Name##TakeStrong(valueAddr, \ + getPayloadType(), \ + Refcounting)); \ + emitLoadOfTables(IGF, existential, out); \ + } \ + } \ + void name##Init(IRGenFunction &IGF, Explosion &in, \ + Address existential, bool isOptional) const override { \ + llvm::Value *value = nullptr; \ + if (isOptional) { \ + Explosion temp; \ + decomposeExplosion(in, temp, IGF); \ + value = temp.claimNext(); \ + assert(value->getType() == IGF.IGM.getReferenceType(Refcounting)); \ + emitStoreOfTables(IGF, temp, existential); \ + } else { \ + value = in.claimNext(); \ + emitStoreOfTables(IGF, in, existential); \ + } \ + Address valueAddr = projectValue(IGF, existential); \ + IGF.emit##Name##Init(value, valueAddr, Refcounting); \ + } \ + void name##Assign(IRGenFunction &IGF, Explosion &in, \ + Address existential, bool isOptional) const override { \ + llvm::Value *value = nullptr; \ + if (isOptional) { \ + Explosion temp; \ + decomposeExplosion(in, temp, IGF); \ + value = temp.claimNext(); \ + assert(value->getType() == IGF.IGM.getReferenceType(Refcounting)); \ + emitStoreOfTables(IGF, temp, existential); \ + } else { \ + value = in.claimNext(); \ + emitStoreOfTables(IGF, in, existential); \ + } \ + Address valueAddr = projectValue(IGF, existential); \ + IGF.emit##Name##Assign(value, valueAddr, Refcounting); \ } - - void strongRetainUnownedRelease(IRGenFunction &IGF, - Explosion &e, - Atomicity atomicity) const override { - IGF.emitStrongRetainAndUnownedRelease(e.claimNext(), Refcounting, - atomicity); - (void)e.claim(getNumStoredProtocols()); +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + void name##Retain(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + IGF.emit##Name##Retain(e.claimNext(), Refcounting, atomicity); \ + (void)e.claim(getNumStoredProtocols()); \ + } \ + void name##Release(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + IGF.emit##Name##Release(e.claimNext(), Refcounting, atomicity); \ + (void)e.claim(getNumStoredProtocols()); \ + } \ + void strongRetain##Name(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + IGF.emitStrongRetain##Name(e.claimNext(), Refcounting, atomicity); \ + (void)e.claim(getNumStoredProtocols()); \ + } \ + void strongRetain##Name##Release(IRGenFunction &IGF, \ + Explosion &e, \ + Atomicity atomicity) const override { \ + IGF.emitStrongRetainAnd##Name##Release(e.claimNext(), Refcounting, \ + atomicity); \ + (void)e.claim(getNumStoredProtocols()); \ } - - void unownedRetain(IRGenFunction &IGF, Explosion &e, - Atomicity atomicity) const override { - IGF.emitUnownedRetain(e.claimNext(), Refcounting, atomicity); - (void)e.claim(getNumStoredProtocols()); +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + const TypeInfo * \ + create##Name##StorageType(TypeConverter &TC, \ + bool isOptional) const override { \ + auto spareBits = TC.IGM.getReferenceStorageSpareBits( \ + ReferenceOwnership::Name, \ + Refcounting); \ + for (unsigned i = 0, e = getNumStoredProtocols(); i != e; ++i) \ + spareBits.append(TC.IGM.getWitnessTablePtrSpareBits()); \ + auto storageTy = buildReferenceStorageType(TC.IGM, \ + TC.IGM.Name##ReferencePtrTy->getElementType()); \ + return AddressOnly##Name##ClassExistentialTypeInfo::create( \ + getStoredProtocols(), \ + storageTy, \ + std::move(spareBits), \ + getFixedSize(), \ + getFixedAlignment(), \ + Refcounting, \ + isOptional); \ } - - void unownedRelease(IRGenFunction &IGF, Explosion &e, - Atomicity atomicity) const override { - IGF.emitUnownedRelease(e.claimNext(), Refcounting, atomicity); - (void)e.claim(getNumStoredProtocols()); +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + const TypeInfo * \ + create##Name##StorageType(TypeConverter &TC, \ + bool isOptional) const override { \ + auto spareBits = TC.IGM.getReferenceStorageSpareBits( \ + ReferenceOwnership::Name, \ + Refcounting); \ + for (unsigned i = 0, e = getNumStoredProtocols(); i != e; ++i) \ + spareBits.append(TC.IGM.getWitnessTablePtrSpareBits()); \ + auto storageTy = buildReferenceStorageType(TC.IGM, \ + TC.IGM.Name##ReferencePtrTy->getElementType()); \ + if (TC.IGM.isLoadableReferenceAddressOnly(Refcounting)) { \ + return AddressOnly##Name##ClassExistentialTypeInfo::create( \ + getStoredProtocols(), \ + storageTy, \ + std::move(spareBits), \ + getFixedSize(), \ + getFixedAlignment(), \ + Refcounting, \ + isOptional); \ + } else { \ + return Loadable##Name##ClassExistentialTypeInfo::create( \ + getStoredProtocols(), \ + getValueType(), \ + storageTy, \ + std::move(spareBits), \ + getFixedSize(), \ + getFixedAlignment(), \ + Refcounting, \ + isOptional); \ + } \ } - - void unownedLoadStrong(IRGenFunction &IGF, Address existential, - Explosion &out) const override { - Address valueAddr = projectValue(IGF, existential); - out.add(IGF.emitUnownedLoadStrong(valueAddr, - getPayloadType(), - Refcounting)); - emitLoadOfTables(IGF, existential, out); +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + const TypeInfo * \ + create##Name##StorageType(TypeConverter &TC, \ + bool isOptional) const override { \ + assert(Refcounting == ReferenceCounting::Native); \ + auto spareBits = TC.IGM.getReferenceStorageSpareBits( \ + ReferenceOwnership::Name, \ + ReferenceCounting::Native); \ + for (unsigned i = 0, e = getNumStoredProtocols(); i != e; ++i) \ + spareBits.append(TC.IGM.getWitnessTablePtrSpareBits()); \ + auto storageTy = buildReferenceStorageType(TC.IGM, \ + TC.IGM.Name##ReferencePtrTy->getElementType()); \ + return Loadable##Name##ClassExistentialTypeInfo::create( \ + getStoredProtocols(), \ + getValueType(), \ + storageTy, \ + std::move(spareBits), \ + getFixedSize(), \ + getFixedAlignment(), \ + ReferenceCounting::Native, \ + isOptional); \ } - - void unownedTakeStrong(IRGenFunction &IGF, Address existential, - Explosion &out) const override { - Address valueAddr = projectValue(IGF, existential); - out.add(IGF.emitUnownedTakeStrong(valueAddr, - getPayloadType(), - Refcounting)); - emitLoadOfTables(IGF, existential, out); - } - - void unownedInit(IRGenFunction &IGF, Explosion &in, - Address existential) const override { - llvm::Value *value = in.claimNext(); - emitStoreOfTables(IGF, in, existential); - Address valueAddr = projectValue(IGF, existential); - IGF.emitUnownedInit(value, valueAddr, Refcounting); - } - - void unownedAssign(IRGenFunction &IGF, Explosion &in, - Address existential) const override { - llvm::Value *value = in.claimNext(); - emitStoreOfTables(IGF, in, existential); - Address valueAddr = projectValue(IGF, existential); - IGF.emitUnownedAssign(value, valueAddr, Refcounting); +#define UNCHECKED_REF_STORAGE(Name, ...) \ + const TypeInfo * \ + create##Name##StorageType(TypeConverter &TC, \ + bool isOptional) const override { \ + return Name##ClassExistentialTypeInfo::create(getStoredProtocols(), \ + getStorageType(), \ + getSpareBits(), \ + getFixedSize(), \ + getFixedAlignment(), \ + isOptional); \ } +#include "swift/AST/ReferenceStorage.def" +#undef NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER +#undef ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER void emitValueRetain(IRGenFunction &IGF, llvm::Value *value, Atomicity atomicity) const { @@ -1208,71 +1237,6 @@ public: return LoadedRef(IGF.emitLoadRefcountedPtr(valueAddr, Refcounting), true); } - const TypeInfo * - createUnownedStorageType(TypeConverter &TC) const override { - // We can just re-use the storage type for the @unowned(safe) type. - - SpareBitVector spareBits = - TC.IGM.getUnownedReferenceSpareBits(Refcounting); - for (unsigned i = 0, e = getNumStoredProtocols(); i != e; ++i) - spareBits.append(TC.IGM.getWitnessTablePtrSpareBits()); - - auto storageTy = buildReferenceStorageType(TC.IGM, - TC.IGM.UnownedReferencePtrTy->getElementType()); - - if (TC.IGM.isUnownedReferenceAddressOnly(Refcounting)) { - return AddressOnlyUnownedClassExistentialTypeInfo::create( - getStoredProtocols(), - storageTy, - std::move(spareBits), - getFixedSize(), - getFixedAlignment(), - Refcounting); - } else { - return LoadableUnownedClassExistentialTypeInfo::create( - getStoredProtocols(), - getValueType(), - storageTy, - std::move(spareBits), - getFixedSize(), - getFixedAlignment(), - Refcounting); - } - } - - const TypeInfo * - createUnmanagedStorageType(TypeConverter &TC) const override { - // We can just re-use the storage type for the @unowned(unsafe) type. - return UnmanagedClassExistentialTypeInfo::create(getStoredProtocols(), - getStorageType(), - getSpareBits(), - getFixedSize(), - getFixedAlignment()); - } - - const WeakTypeInfo * - createWeakStorageType(TypeConverter &TC) const override { - Size size = TC.IGM.getWeakReferenceSize() - + getNumStoredProtocols() * TC.IGM.getPointerSize(); - - Alignment align = TC.IGM.getWeakReferenceAlignment(); - assert(align == TC.IGM.getPointerAlignment() && - "[weak] alignment not pointer alignment; fix existential layout"); - (void)align; - - auto storageTy = buildReferenceStorageType(TC.IGM, - TC.IGM.WeakReferencePtrTy->getElementType()); - - SpareBitVector spareBits = TC.IGM.getWeakReferenceSpareBits(); - for (unsigned i = 0, e = getNumStoredProtocols(); i != e; ++i) - spareBits.append(TC.IGM.getWitnessTablePtrSpareBits()); - - return WeakClassExistentialTypeInfo::create(getStoredProtocols(), - storageTy, size, align, - std::move(spareBits), - Refcounting); - } - llvm::StructType *buildReferenceStorageType(IRGenModule &IGM, llvm::Type *refStorageTy) const { SmallVector fieldTys; @@ -1509,7 +1473,7 @@ TypeConverter::convertExistentialMetatypeType(ExistentialMetatypeType *T) { assert(T->getRepresentation() != MetatypeRepresentation::Thin && "existential metatypes cannot have thin representation"); - auto &baseTI = getMetatypeTypeInfo(T->getRepresentation()); + auto &baseTI = cast(getMetatypeTypeInfo(T->getRepresentation())); fields.push_back(baseTI.getStorageType()); spareBits.append(baseTI.getSpareBits()); diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index eeb67352dfd..543eb7f7d47 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -198,18 +198,13 @@ namespace { } // Function types do not satisfy allowsOwnership. - const WeakTypeInfo * - createWeakStorageType(TypeConverter &TC) const override { - llvm_unreachable("[weak] function type"); - } - const TypeInfo * - createUnownedStorageType(TypeConverter &TC) const override { - llvm_unreachable("[unowned] function type"); - } - const TypeInfo * - createUnmanagedStorageType(TypeConverter &TC) const override { - llvm_unreachable("@unowned(unsafe) function type"); +#define REF_STORAGE(Name, name, ...) \ + const TypeInfo * \ + create##Name##StorageType(TypeConverter &TC, \ + bool isOptional) const override { \ + llvm_unreachable("[" #name "] function type"); \ } +#include "swift/AST/ReferenceStorage.def" llvm::StructType *getStorageType() const { return cast(TypeInfo::getStorageType()); @@ -335,46 +330,45 @@ namespace { IGF.emitNativeStrongRelease(context, atomicity); } - void strongRetainUnowned(IRGenFunction &IGF, Explosion &e, - Atomicity atomicity) const override { - llvm_unreachable("unowned references to functions are not supported"); +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + void name##LoadStrong(IRGenFunction &IGF, Address src, \ + Explosion &out, bool isOptional) const override { \ + llvm_unreachable(#name " references to functions are not supported"); \ + } \ + void name##TakeStrong(IRGenFunction &IGF, Address src, \ + Explosion &out, bool isOptional) const override { \ + llvm_unreachable(#name " references to functions are not supported"); \ + } \ + void name##Init(IRGenFunction &IGF, Explosion &in, \ + Address dest, bool isOptional) const override { \ + llvm_unreachable(#name " references to functions are not supported"); \ + } \ + void name##Assign(IRGenFunction &IGF, Explosion &in, \ + Address dest, bool isOptional) const override { \ + llvm_unreachable(#name " references to functions are not supported"); \ } - - void strongRetainUnownedRelease(IRGenFunction &IGF, - Explosion &e, - Atomicity atomicity) const override { - llvm_unreachable("unowned references to functions are not supported"); - } - - void unownedRetain(IRGenFunction &IGF, Explosion &e, - Atomicity atomicity) const override { - llvm_unreachable("unowned references to functions are not supported"); - } - - void unownedRelease(IRGenFunction &IGF, Explosion &e, - Atomicity atomicity) const override { - llvm_unreachable("unowned references to functions are not supported"); - } - - void unownedLoadStrong(IRGenFunction &IGF, Address src, - Explosion &out) const override { - llvm_unreachable("unowned references to functions are not supported"); - } - - void unownedTakeStrong(IRGenFunction &IGF, Address src, - Explosion &out) const override { - llvm_unreachable("unowned references to functions are not supported"); - } - - void unownedInit(IRGenFunction &IGF, Explosion &in, - Address dest) const override { - llvm_unreachable("unowned references to functions are not supported"); - } - - void unownedAssign(IRGenFunction &IGF, Explosion &in, - Address dest) const override { - llvm_unreachable("unowned references to functions are not supported"); +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + void strongRetain##Name(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + llvm_unreachable(#name " references to functions are not supported"); \ + } \ + void strongRetain##Name##Release(IRGenFunction &IGF, \ + Explosion &e, \ + Atomicity atomicity) const override { \ + llvm_unreachable(#name " references to functions are not supported"); \ + } \ + void name##Retain(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + llvm_unreachable(#name " references to functions are not supported"); \ + } \ + void name##Release(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + llvm_unreachable(#name " references to functions are not supported"); \ } +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") +#include "swift/AST/ReferenceStorage.def" void destroy(IRGenFunction &IGF, Address addr, SILType T, bool isOutlined) const override { diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index 1fa102dc681..49ea3ee23df 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -39,13 +39,196 @@ #include "HeapTypeInfo.h" #include "IndirectTypeInfo.h" #include "MetadataRequest.h" -#include "WeakTypeInfo.h" #include "GenHeap.h" using namespace swift; using namespace irgen; +namespace { +#define NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Nativeness) \ + class Nativeness##Name##ReferenceTypeInfo \ + : public IndirectTypeInfo { \ + llvm::PointerIntPair ValueTypeAndIsOptional; \ + public: \ + Nativeness##Name##ReferenceTypeInfo(llvm::Type *valueType, \ + llvm::Type *type, \ + Size size, Alignment alignment, \ + SpareBitVector &&spareBits, \ + bool isOptional) \ + : IndirectTypeInfo(type, size, std::move(spareBits), alignment, \ + IsNotPOD, IsNotBitwiseTakable, IsFixedSize), \ + ValueTypeAndIsOptional(valueType, isOptional) {} \ + void initializeWithCopy(IRGenFunction &IGF, Address destAddr, \ + Address srcAddr, SILType T, \ + bool isOutlined) const override { \ + IGF.emit##Nativeness##Name##CopyInit(destAddr, srcAddr); \ + } \ + void initializeWithTake(IRGenFunction &IGF, Address destAddr, \ + Address srcAddr, SILType T, \ + bool isOutlined) const override { \ + IGF.emit##Nativeness##Name##TakeInit(destAddr, srcAddr); \ + } \ + void assignWithCopy(IRGenFunction &IGF, Address destAddr, Address srcAddr, \ + SILType T, bool isOutlined) const override { \ + IGF.emit##Nativeness##Name##CopyAssign(destAddr, srcAddr); \ + } \ + void assignWithTake(IRGenFunction &IGF, Address destAddr, Address srcAddr, \ + SILType T, bool isOutlined) const override { \ + IGF.emit##Nativeness##Name##TakeAssign(destAddr, srcAddr); \ + } \ + void destroy(IRGenFunction &IGF, Address addr, SILType T, \ + bool isOutlined) const override { \ + IGF.emit##Nativeness##Name##Destroy(addr); \ + } \ + unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { \ + auto count = IGM.getReferenceStorageExtraInhabitantCount( \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + return count - ValueTypeAndIsOptional.getInt(); \ + } \ + APInt getFixedExtraInhabitantValue(IRGenModule &IGM, \ + unsigned bits, \ + unsigned index) const override { \ + return IGM.getReferenceStorageExtraInhabitantValue(bits, \ + index + ValueTypeAndIsOptional.getInt(), \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + } \ + llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, \ + SILType T) const override { \ + return IGF.getReferenceStorageExtraInhabitantIndex(src, \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + } \ + void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, \ + Address dest, SILType T) const override { \ + return IGF.storeReferenceStorageExtraInhabitant(index, dest, \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + } \ + APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override { \ + return IGM.getReferenceStorageExtraInhabitantMask( \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + } \ + llvm::Type *getOptionalIntType() const { \ + return llvm::IntegerType::get( \ + ValueTypeAndIsOptional.getPointer()->getContext(), \ + getFixedSize().getValueInBits()); \ + } \ + }; +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Nativeness) \ + class Nativeness##Name##ReferenceTypeInfo \ + : public SingleScalarTypeInfo { \ + llvm::PointerIntPair ValueTypeAndIsOptional; \ + public: \ + Nativeness##Name##ReferenceTypeInfo(llvm::Type *valueType, \ + llvm::Type *type, \ + Size size, Alignment alignment, \ + SpareBitVector &&spareBits, \ + bool isOptional) \ + : SingleScalarTypeInfo(type, size, std::move(spareBits), \ + alignment, IsNotPOD, IsFixedSize), \ + ValueTypeAndIsOptional(valueType, isOptional) {} \ + enum { IsScalarPOD = false }; \ + llvm::Type *getScalarType() const { \ + return ValueTypeAndIsOptional.getPointer(); \ + } \ + Address projectScalar(IRGenFunction &IGF, Address addr) const { \ + return IGF.Builder.CreateBitCast(addr, getScalarType()->getPointerTo()); \ + } \ + void emitScalarRetain(IRGenFunction &IGF, llvm::Value *value, \ + Atomicity atomicity) const { \ + IGF.emit##Nativeness##Name##Retain(value, atomicity); \ + } \ + void emitScalarRelease(IRGenFunction &IGF, llvm::Value *value, \ + Atomicity atomicity) const { \ + IGF.emit##Nativeness##Name##Release(value, atomicity); \ + } \ + void emitScalarFixLifetime(IRGenFunction &IGF, llvm::Value *value) const { \ + IGF.emitFixLifetime(value); \ + } \ + unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { \ + auto count = IGM.getReferenceStorageExtraInhabitantCount( \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + return count - ValueTypeAndIsOptional.getInt(); \ + } \ + APInt getFixedExtraInhabitantValue(IRGenModule &IGM, \ + unsigned bits, \ + unsigned index) const override { \ + return IGM.getReferenceStorageExtraInhabitantValue(bits, \ + index + ValueTypeAndIsOptional.getInt(), \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + } \ + llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, \ + SILType T) const override { \ + return IGF.getReferenceStorageExtraInhabitantIndex(src, \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + } \ + void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, \ + Address dest, SILType T) const override { \ + return IGF.storeReferenceStorageExtraInhabitant(index, dest, \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + } \ + APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override { \ + return IGM.getReferenceStorageExtraInhabitantMask( \ + ReferenceOwnership::Name, \ + ReferenceCounting::Nativeness); \ + } \ + }; + + // The nativeness of a reference storage type is a policy decision. + // Please also see the related ALWAYS_NATIVE and SOMETIMES_UNKNOWN macros + // later in this file that expand to the following boilerplate: + // TypeConverter::create##Name##StorageType + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Weak, Native) + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Weak, Unknown) + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Unowned, Unknown) + ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Unowned, Native) +#undef NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER +#undef ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER + +#define UNCHECKED_REF_STORAGE(Name, ...) \ + class Name##ReferenceTypeInfo \ + : public PODSingleScalarTypeInfo { \ + bool IsOptional; \ + public: \ + Name##ReferenceTypeInfo(llvm::Type *type, \ + const SpareBitVector &spareBits, \ + Size size, Alignment alignment, bool isOptional) \ + : PODSingleScalarTypeInfo(type, size, spareBits, alignment), \ + IsOptional(isOptional) {} \ + /* Static types have the same spare bits as managed heap objects. */ \ + unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { \ + return getHeapObjectExtraInhabitantCount(IGM) - IsOptional; \ + } \ + APInt getFixedExtraInhabitantValue(IRGenModule &IGM, \ + unsigned bits, \ + unsigned index) const override { \ + return getHeapObjectFixedExtraInhabitantValue(IGM, bits, \ + index + IsOptional, 0); \ + } \ + llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, \ + SILType T) \ + const override { \ + return getHeapObjectExtraInhabitantIndex(IGF, src); \ + } \ + void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, \ + Address dest, SILType T) const override { \ + return storeHeapObjectExtraInhabitant(IGF, index, dest); \ + } \ + }; +#include "swift/AST/ReferenceStorage.def" +} // end anonymous namespace + /// Produce a constant to place in a metatype's isa field /// corresponding to the given metadata kind. static llvm::ConstantInt *getMetadataKind(IRGenModule &IGM, @@ -367,259 +550,133 @@ const LoadableTypeInfo *TypeConverter::convertBuiltinNativeObject() { IGM.getPointerAlignment()); } -namespace { - /// A type implementation for an @unowned(unsafe) reference to an - /// object. - class UnmanagedReferenceTypeInfo - : public PODSingleScalarTypeInfo { - public: - UnmanagedReferenceTypeInfo(llvm::Type *type, - const SpareBitVector &spareBits, - Size size, Alignment alignment) - : PODSingleScalarTypeInfo(type, size, spareBits, alignment) {} - - // Unmanaged types have the same spare bits as managed heap objects. - - bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { - return true; - } - - unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { - return getHeapObjectExtraInhabitantCount(IGM); - } - - APInt getFixedExtraInhabitantValue(IRGenModule &IGM, - unsigned bits, - unsigned index) const override { - return getHeapObjectFixedExtraInhabitantValue(IGM, bits, index, 0); - } - - llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, - SILType T) - const override { - return getHeapObjectExtraInhabitantIndex(IGF, src); - } - - void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, - Address dest, SILType T) const override { - return storeHeapObjectExtraInhabitant(IGF, index, dest); - } - }; -} // end anonymous namespace - -const LoadableTypeInfo * -TypeConverter::createUnmanagedStorageType(llvm::Type *valueType) { - return new UnmanagedReferenceTypeInfo(valueType, - IGM.getHeapObjectSpareBits(), - IGM.getPointerSize(), - IGM.getPointerAlignment()); -} - -namespace { - /// A type implementation for an [unowned] reference to an object - /// with a known-Swift reference count. - class NativeUnownedReferenceTypeInfo - : public SingleScalarTypeInfo { - llvm::Type *ValueType; - public: - NativeUnownedReferenceTypeInfo(llvm::Type *valueType, - llvm::Type *unownedType, - SpareBitVector &&spareBits, - Size size, Alignment alignment) - : SingleScalarTypeInfo(unownedType, size, std::move(spareBits), - alignment, IsNotPOD, IsFixedSize), - ValueType(valueType) {} - - enum { IsScalarPOD = false }; - - llvm::Type *getScalarType() const { - return ValueType; - } - - Address projectScalar(IRGenFunction &IGF, Address addr) const { - return IGF.Builder.CreateBitCast(addr, ValueType->getPointerTo()); - } - - void emitScalarRetain(IRGenFunction &IGF, llvm::Value *value, - Atomicity atomicity) const { - IGF.emitNativeUnownedRetain(value, atomicity); - } - - void emitScalarRelease(IRGenFunction &IGF, llvm::Value *value, - Atomicity atomicity) const { - IGF.emitNativeUnownedRelease(value, atomicity); - } - - void emitScalarFixLifetime(IRGenFunction &IGF, llvm::Value *value) const { - IGF.emitFixLifetime(value); - } - - unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { - return IGM.getUnownedExtraInhabitantCount(ReferenceCounting::Native); - } - - APInt getFixedExtraInhabitantValue(IRGenModule &IGM, - unsigned bits, - unsigned index) const override { - return IGM.getUnownedExtraInhabitantValue(bits, index, - ReferenceCounting::Native); - } - - llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, - SILType T) const override { - return IGF.getUnownedExtraInhabitantIndex(src, - ReferenceCounting::Native); - } - - void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, - Address dest, SILType T) const override { - return IGF.storeUnownedExtraInhabitant(index, dest, - ReferenceCounting::Native); - } - - APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override { - return IGM.getUnownedExtraInhabitantMask(ReferenceCounting::Native); - - } - }; - - /// A type implementation for a [weak] reference to an object - /// with a known-Swift reference count. - class NativeWeakReferenceTypeInfo - : public IndirectTypeInfo { - llvm::Type *ValueType; - public: - NativeWeakReferenceTypeInfo(llvm::Type *valueType, - llvm::Type *weakType, - Size size, Alignment alignment, - SpareBitVector &&spareBits) - : IndirectTypeInfo(weakType, size, alignment, std::move(spareBits)), - ValueType(valueType) {} - - void initializeWithCopy(IRGenFunction &IGF, Address destAddr, - Address srcAddr, SILType T, - bool isOutlined) const override { - IGF.emitNativeWeakCopyInit(destAddr, srcAddr); - } - - void initializeWithTake(IRGenFunction &IGF, Address destAddr, - Address srcAddr, SILType T, - bool isOutlined) const override { - IGF.emitNativeWeakTakeInit(destAddr, srcAddr); - } - - void assignWithCopy(IRGenFunction &IGF, Address destAddr, Address srcAddr, - SILType T, bool isOutlined) const override { - IGF.emitNativeWeakCopyAssign(destAddr, srcAddr); - } - - void assignWithTake(IRGenFunction &IGF, Address destAddr, Address srcAddr, - SILType T, bool isOutlined) const override { - IGF.emitNativeWeakTakeAssign(destAddr, srcAddr); - } - - void destroy(IRGenFunction &IGF, Address addr, SILType T, - bool isOutlined) const override { - IGF.emitNativeWeakDestroy(addr); - } - - llvm::Type *getOptionalIntType() const { - return llvm::IntegerType::get(ValueType->getContext(), - getFixedSize().getValueInBits()); - } - - void weakLoadStrong(IRGenFunction &IGF, Address addr, - Explosion &out) const override { - auto value = IGF.emitNativeWeakLoadStrong(addr, ValueType); - // The optional will be lowered to an integer type the size of the word. - out.add(IGF.Builder.CreatePtrToInt(value, getOptionalIntType())); - } - - void weakTakeStrong(IRGenFunction &IGF, Address addr, - Explosion &out) const override { - auto value = IGF.emitNativeWeakTakeStrong(addr, ValueType); - // The optional will be lowered to an integer type the size of the word. - out.add(IGF.Builder.CreatePtrToInt(value, getOptionalIntType())); - } - - void weakInit(IRGenFunction &IGF, Explosion &in, - Address dest) const override { - llvm::Value *value = in.claimNext(); - // The optional will be lowered to an integer type the size of the word. - assert(value->getType() == getOptionalIntType()); - value = IGF.Builder.CreateIntToPtr(value, ValueType); - IGF.emitNativeWeakInit(value, dest); - } - - void weakAssign(IRGenFunction &IGF, Explosion &in, - Address dest) const override { - llvm::Value *value = in.claimNext(); - // The optional will be lowered to an integer type the size of the word. - assert(value->getType() == getOptionalIntType()); - value = IGF.Builder.CreateIntToPtr(value, ValueType); - IGF.emitNativeWeakAssign(value, dest); - } - }; -} // end anonymous namespace - -SpareBitVector IRGenModule::getWeakReferenceSpareBits() const { - // The runtime needs to be able to freely manipulate live weak - // references without worrying about us mucking around with their - // bits, so weak references are completely opaque. - return SpareBitVector::getConstant(getWeakReferenceSize().getValueInBits(), - false); -} - -SpareBitVector -IRGenModule::getUnownedReferenceSpareBits(ReferenceCounting style) const { - // If unknown references don't exist, we can just use the same rules as - // regular pointers. - if (!ObjCInterop) { - assert(style == ReferenceCounting::Native); - return getHeapObjectSpareBits(); - } - - // Otherwise, we have to be conservative (even with native - // reference-counting) in order to interoperate with code that might - // be working more generically with the memory/type. - return SpareBitVector::getConstant(getPointerSize().getValueInBits(), false); -} - -unsigned IRGenModule::getUnownedExtraInhabitantCount(ReferenceCounting style) { - if (!ObjCInterop) { - assert(style == ReferenceCounting::Native); +unsigned IRGenModule::getReferenceStorageExtraInhabitantCount( + ReferenceOwnership ownership, + ReferenceCounting style) const { + switch (style) { + case ReferenceCounting::Native: +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + if (ownership == ReferenceOwnership::Name) \ + break; +#include "swift/AST/ReferenceStorage.def" + if (ObjCInterop) + break; return getHeapObjectExtraInhabitantCount(*this); + case ReferenceCounting::Block: + case ReferenceCounting::ObjC: + case ReferenceCounting::Unknown: + break; + case ReferenceCounting::Bridge: + case ReferenceCounting::Error: + llvm_unreachable("Unsupported reference-counting style"); } + // The default behavior uses pointer semantics, therefore null is the only + // extra inhabitant allowed. return 1; } -APInt IRGenModule::getUnownedExtraInhabitantValue(unsigned bits, unsigned index, - ReferenceCounting style) { - if (!ObjCInterop) { - assert(style == ReferenceCounting::Native); - return getHeapObjectFixedExtraInhabitantValue(*this, bits, index, 0); +SpareBitVector IRGenModule::getReferenceStorageSpareBits( + ReferenceOwnership ownership, + ReferenceCounting style) const { + // We have to be conservative (even with native reference-counting) in order + // to interoperate with code that might be working more generically with the + // memory/type. + switch (style) { + case ReferenceCounting::Native: +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + if (ownership == ReferenceOwnership::Name) \ + break; +#include "swift/AST/ReferenceStorage.def" + if (ObjCInterop) + break; + return getHeapObjectSpareBits(); + case ReferenceCounting::Block: + case ReferenceCounting::ObjC: + case ReferenceCounting::Unknown: + break; + case ReferenceCounting::Bridge: + case ReferenceCounting::Error: + llvm_unreachable("Unsupported reference-counting style"); } + // The default behavior uses pointer semantics. + return SpareBitVector::getConstant(getPointerSize().getValueInBits(), false); +} + +APInt IRGenModule::getReferenceStorageExtraInhabitantValue(unsigned bits, + unsigned index, + ReferenceOwnership ownership, + ReferenceCounting style) const { + // We have to be conservative (even with native reference-counting) in order + // to interoperate with code that might be working more generically with the + // memory/type. + switch (style) { + case ReferenceCounting::Native: +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + if (ownership == ReferenceOwnership::Name) \ + break; +#include "swift/AST/ReferenceStorage.def" + if (ObjCInterop) + break; + return getHeapObjectFixedExtraInhabitantValue(*this, bits, index, 0); + case ReferenceCounting::Block: + case ReferenceCounting::ObjC: + case ReferenceCounting::Unknown: + break; + case ReferenceCounting::Bridge: + case ReferenceCounting::Error: + llvm_unreachable("Unsupported reference-counting style"); + } + + // The default behavior allows for only one legal extra inhabitant, therefore + // this must be the null pattern. assert(index == 0); return APInt(bits, 0); } -APInt IRGenModule::getUnownedExtraInhabitantMask(ReferenceCounting style) { +APInt IRGenModule::getReferenceStorageExtraInhabitantMask( + ReferenceOwnership ownership, + ReferenceCounting style) const { + switch (style) { + case ReferenceCounting::Native: + case ReferenceCounting::Block: + case ReferenceCounting::ObjC: + case ReferenceCounting::Unknown: + break; + case ReferenceCounting::Bridge: + case ReferenceCounting::Error: + llvm_unreachable("Unsupported reference-counting style"); + } return APInt::getAllOnesValue(getPointerSize().getValueInBits()); } -llvm::Value *IRGenFunction::getUnownedExtraInhabitantIndex(Address src, - ReferenceCounting style) { - if (!IGM.ObjCInterop) { - assert(style == ReferenceCounting::Native); +llvm::Value *IRGenFunction::getReferenceStorageExtraInhabitantIndex(Address src, + ReferenceOwnership ownership, + ReferenceCounting style) { + switch (style) { + case ReferenceCounting::Native: + if (IGM.ObjCInterop) + break; return getHeapObjectExtraInhabitantIndex(*this, src); + case ReferenceCounting::Block: + case ReferenceCounting::ObjC: + case ReferenceCounting::Unknown: + break; + case ReferenceCounting::Bridge: + case ReferenceCounting::Error: + llvm_unreachable("Unsupported reference-counting style"); } - assert(src.getAddress()->getType() == IGM.UnownedReferencePtrTy); + // The default behavior allows for only one legal extra inhabitant, therefore + // this must be the null pattern. + auto PtrTy = +#define CHECKED_REF_STORAGE(Name, ...) \ + ownership == ReferenceOwnership::Name ? IGM.Name##ReferencePtrTy : +#include "swift/AST/ReferenceStorage.def" + nullptr; + (void)PtrTy; + assert(src.getAddress()->getType() == PtrTy); src = Builder.CreateStructGEP(src, 0, Size(0)); llvm::Value *ptr = Builder.CreateLoad(src); llvm::Value *isNull = Builder.CreateIsNull(ptr); @@ -629,221 +686,107 @@ llvm::Value *IRGenFunction::getUnownedExtraInhabitantIndex(Address src, return result; } -void IRGenFunction::storeUnownedExtraInhabitant(llvm::Value *index, - Address dest, - ReferenceCounting style) { - if (!IGM.ObjCInterop) { - assert(style == ReferenceCounting::Native); +void IRGenFunction::storeReferenceStorageExtraInhabitant(llvm::Value *index, + Address dest, + ReferenceOwnership ownership, + ReferenceCounting style) { + switch (style) { + case ReferenceCounting::Native: + if (IGM.ObjCInterop) + break; return storeHeapObjectExtraInhabitant(*this, index, dest); + case ReferenceCounting::Block: + case ReferenceCounting::ObjC: + case ReferenceCounting::Unknown: + break; + case ReferenceCounting::Bridge: + case ReferenceCounting::Error: + llvm_unreachable("Unsupported reference-counting style"); } - // Since there's only one legal extra inhabitant, it has to have - // the null pattern. - assert(dest.getAddress()->getType() == IGM.UnownedReferencePtrTy); + // The default behavior allows for only one legal extra inhabitant, therefore + // this must be the null pattern. + auto PtrTy = +#define CHECKED_REF_STORAGE(Name, ...) \ + ownership == ReferenceOwnership::Name ? IGM.Name##ReferencePtrTy : +#include "swift/AST/ReferenceStorage.def" + nullptr; + (void)PtrTy; + assert(dest.getAddress()->getType() == PtrTy); dest = Builder.CreateStructGEP(dest, 0, Size(0)); llvm::Value *null = llvm::ConstantPointerNull::get(IGM.RefCountedPtrTy); Builder.CreateStore(null, dest); } -namespace { - /// A type implementation for an [unowned] reference to an object - /// that is not necessarily a Swift object. - class UnknownUnownedReferenceTypeInfo : - public IndirectTypeInfo { - public: - UnknownUnownedReferenceTypeInfo(llvm::Type *unownedType, - SpareBitVector &&spareBits, - Size size, Alignment alignment) - : IndirectTypeInfo(unownedType, size, std::move(spareBits), alignment, - IsNotPOD, IsNotBitwiseTakable, IsFixedSize) { - } - - void assignWithCopy(IRGenFunction &IGF, Address dest, Address src, - SILType type, bool isOutlined) const override { - IGF.emitUnknownUnownedCopyAssign(dest, src); - } - - void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src, - SILType type, bool isOutlined) const override { - IGF.emitUnknownUnownedCopyInit(dest, src); - } - - void assignWithTake(IRGenFunction &IGF, Address dest, Address src, - SILType type, bool isOutlined) const override { - IGF.emitUnknownUnownedTakeAssign(dest, src); - } - - void initializeWithTake(IRGenFunction &IGF, Address dest, Address src, - SILType type, bool isOutlined) const override { - IGF.emitUnknownUnownedTakeInit(dest, src); - } - - void destroy(IRGenFunction &IGF, Address addr, SILType type, - bool isOutlined) const override { - IGF.emitUnknownUnownedDestroy(addr); - } - - // Unowned types have the same extra inhabitants as normal pointers. - // They do not, however, necessarily have any spare bits. - - unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override { - return IGM.getUnownedExtraInhabitantCount(ReferenceCounting::Unknown); - } - - APInt getFixedExtraInhabitantValue(IRGenModule &IGM, - unsigned bits, - unsigned index) const override { - return IGM.getUnownedExtraInhabitantValue(bits, index, - ReferenceCounting::Unknown); - } - - llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src, - SILType T) const override { - return IGF.getUnownedExtraInhabitantIndex(src, - ReferenceCounting::Unknown); - } - - void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index, - Address dest, SILType T) const override { - return IGF.storeUnownedExtraInhabitant(index, dest, - ReferenceCounting::Unknown); - } - - APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override { - return IGM.getUnownedExtraInhabitantMask(ReferenceCounting::Unknown); - } - }; - - /// A type implementation for a [weak] reference to an object - /// that is not necessarily a Swift object. - class UnknownWeakReferenceTypeInfo : - public IndirectTypeInfo { - /// We need to separately store the value type because we always - /// use the same type to store the weak reference struct. - llvm::Type *ValueType; - public: - UnknownWeakReferenceTypeInfo(llvm::Type *valueType, - llvm::Type *weakType, - Size size, Alignment alignment, - SpareBitVector &&spareBits) - : IndirectTypeInfo(weakType, size, alignment, std::move(spareBits)), - ValueType(valueType) {} - - void initializeWithCopy(IRGenFunction &IGF, Address destAddr, - Address srcAddr, SILType T, - bool isOutlined) const override { - IGF.emitUnknownWeakCopyInit(destAddr, srcAddr); - } - - void initializeWithTake(IRGenFunction &IGF, Address destAddr, - Address srcAddr, SILType T, - bool isOutlined) const override { - IGF.emitUnknownWeakTakeInit(destAddr, srcAddr); - } - - void assignWithCopy(IRGenFunction &IGF, Address destAddr, Address srcAddr, - SILType T, bool isOutlined) const override { - IGF.emitUnknownWeakCopyAssign(destAddr, srcAddr); - } - - void assignWithTake(IRGenFunction &IGF, Address destAddr, Address srcAddr, - SILType T, bool isOutlined) const override { - IGF.emitUnknownWeakTakeAssign(destAddr, srcAddr); - } - - void destroy(IRGenFunction &IGF, Address addr, SILType T, - bool isOutlined) const override { - IGF.emitUnknownWeakDestroy(addr); - } - - llvm::Type *getOptionalIntType() const { - return llvm::IntegerType::get(ValueType->getContext(), - getFixedSize().getValueInBits()); - } - - void weakLoadStrong(IRGenFunction &IGF, Address addr, - Explosion &out) const override { - auto value = IGF.emitUnknownWeakLoadStrong(addr, ValueType); - // The optional will be lowered to an integer type the size of the word. - out.add(IGF.Builder.CreatePtrToInt(value, getOptionalIntType())); - } - - void weakTakeStrong(IRGenFunction &IGF, Address addr, - Explosion &out) const override { - auto value = IGF.emitUnknownWeakTakeStrong(addr, ValueType); - // The optional will be lowered to an integer type the size of the word. - out.add(IGF.Builder.CreatePtrToInt(value, getOptionalIntType())); - } - - void weakInit(IRGenFunction &IGF, Explosion &in, - Address dest) const override { - llvm::Value *value = in.claimNext(); - // The optional will be lowered to an integer type the size of the word. - assert(value->getType() == getOptionalIntType()); - value = IGF.Builder.CreateIntToPtr(value, ValueType); - IGF.emitUnknownWeakInit(value, dest); - } - - void weakAssign(IRGenFunction &IGF, Explosion &in, - Address dest) const override { - llvm::Value *value = in.claimNext(); - // The optional will be lowered to an integer type the size of the word. - assert(value->getType() == getOptionalIntType()); - value = IGF.Builder.CreateIntToPtr(value, ValueType); - IGF.emitUnknownWeakAssign(value, dest); - } - }; -} // end anonymous namespace - -const TypeInfo *TypeConverter::createUnownedStorageType(llvm::Type *valueType, - ReferenceCounting style) { - auto &&spareBits = IGM.getUnownedReferenceSpareBits(style); - switch (style) { - case ReferenceCounting::Native: - return new NativeUnownedReferenceTypeInfo(valueType, - IGM.UnownedReferencePtrTy->getElementType(), - std::move(spareBits), - IGM.getPointerSize(), - IGM.getPointerAlignment()); - case ReferenceCounting::ObjC: - case ReferenceCounting::Block: - case ReferenceCounting::Unknown: - return new UnknownUnownedReferenceTypeInfo( - IGM.UnownedReferencePtrTy->getElementType(), - std::move(spareBits), - IGM.getPointerSize(), - IGM.getPointerAlignment()); - case ReferenceCounting::Bridge: - case ReferenceCounting::Error: - llvm_unreachable("not supported!"); +#define SOMETIMES_UNKNOWN(Name) \ + const TypeInfo * \ + TypeConverter::create##Name##StorageType(llvm::Type *valueType, \ + ReferenceCounting style, \ + bool isOptional) { \ + auto &&spareBits = IGM.getReferenceStorageSpareBits( \ + ReferenceOwnership::Name, style); \ + switch (style) { \ + case ReferenceCounting::Native: \ + return new Native##Name##ReferenceTypeInfo(valueType, \ + IGM.Name##ReferencePtrTy->getElementType(), \ + IGM.getPointerSize(), \ + IGM.getPointerAlignment(), \ + std::move(spareBits), \ + isOptional); \ + case ReferenceCounting::ObjC: \ + case ReferenceCounting::Block: \ + case ReferenceCounting::Unknown: \ + return new Unknown##Name##ReferenceTypeInfo(valueType, \ + IGM.Name##ReferencePtrTy->getElementType(), \ + IGM.getPointerSize(), \ + IGM.getPointerAlignment(), \ + std::move(spareBits), \ + isOptional); \ + case ReferenceCounting::Bridge: \ + case ReferenceCounting::Error: \ + llvm_unreachable("not supported!"); \ + } \ + llvm_unreachable("bad reference-counting style"); \ } - llvm_unreachable("bad reference-counting style"); -} - -const WeakTypeInfo *TypeConverter::createWeakStorageType(llvm::Type *valueType, - ReferenceCounting style) { - switch (style) { - case ReferenceCounting::Native: - return new NativeWeakReferenceTypeInfo(valueType, - IGM.WeakReferencePtrTy->getElementType(), - IGM.getWeakReferenceSize(), - IGM.getWeakReferenceAlignment(), - IGM.getWeakReferenceSpareBits()); - case ReferenceCounting::ObjC: - case ReferenceCounting::Block: - case ReferenceCounting::Unknown: - return new UnknownWeakReferenceTypeInfo(valueType, - IGM.WeakReferencePtrTy->getElementType(), - IGM.getWeakReferenceSize(), - IGM.getWeakReferenceAlignment(), - IGM.getWeakReferenceSpareBits()); - case ReferenceCounting::Bridge: - case ReferenceCounting::Error: - llvm_unreachable("not supported!"); +#define ALWAYS_NATIVE(Name) \ + const TypeInfo * \ + TypeConverter::create##Name##StorageType(llvm::Type *valueType, \ + ReferenceCounting style, \ + bool isOptional) { \ + assert(style == ReferenceCounting::Native); \ + auto &&spareBits = IGM.getReferenceStorageSpareBits( \ + ReferenceOwnership::Name, \ + ReferenceCounting::Native); \ + return new Native##Name##ReferenceTypeInfo(valueType, \ + IGM.Name##ReferencePtrTy->getElementType(), \ + IGM.getPointerSize(), \ + IGM.getPointerAlignment(), \ + std::move(spareBits), \ + isOptional); \ } - llvm_unreachable("bad reference-counting style"); -} + + // Always native versus "sometimes unknown" reference storage type policy: + SOMETIMES_UNKNOWN(Weak) + SOMETIMES_UNKNOWN(Unowned) +#undef SOMETIMES_UNKNOWN +#undef ALWAYS_NATIVE + +#define CHECKED_REF_STORAGE(Name, ...) \ + static_assert(&TypeConverter::create##Name##StorageType != nullptr, \ + "Missing reference storage type converter helper constructor"); +#define UNCHECKED_REF_STORAGE(Name, ...) \ + const TypeInfo * \ + TypeConverter::create##Name##StorageType(llvm::Type *valueType, \ + ReferenceCounting style, \ + bool isOptional) { \ + (void)style; /* unused */ \ + return new Name##ReferenceTypeInfo(valueType, \ + IGM.getHeapObjectSpareBits(), \ + IGM.getPointerSize(), \ + IGM.getPointerAlignment(), \ + isOptional); \ + } +#include "swift/AST/ReferenceStorage.def" /// Does the given value superficially not require reference-counting? static bool doesNotRequireRefCounting(llvm::Value *value) { @@ -1107,7 +1050,7 @@ RESULT IRGenFunction::emit##KIND(TYPE1 val1, TYPE2 val2, \ case ReferenceCounting::Bridge: \ case ReferenceCounting::Block: \ case ReferenceCounting::Error: \ - llvm_unreachable("this kind of reference does not support weak/unowned"); \ + llvm_unreachable("unsupported reference kind with reference storage"); \ } \ llvm_unreachable("bad refcounting style"); \ } @@ -1123,65 +1066,126 @@ RESULT IRGenFunction::emit##KIND(TYPE1 val1, ReferenceCounting style) { \ case ReferenceCounting::Bridge: \ case ReferenceCounting::Block: \ case ReferenceCounting::Error: \ - llvm_unreachable("this kind of reference does not support weak/unowned"); \ + llvm_unreachable("unsupported reference kind with reference storage"); \ } \ llvm_unreachable("bad refcounting style"); \ } -DEFINE_BINARY_OPERATION(WeakCopyInit, void, Address, Address) -DEFINE_BINARY_OPERATION(WeakTakeInit, void, Address, Address) -DEFINE_BINARY_OPERATION(WeakCopyAssign, void, Address, Address) -DEFINE_BINARY_OPERATION(WeakTakeAssign, void, Address, Address) -DEFINE_BINARY_OPERATION(WeakInit, void, llvm::Value *, Address) -DEFINE_BINARY_OPERATION(WeakAssign, void, llvm::Value *, Address) -DEFINE_BINARY_OPERATION(WeakLoadStrong, llvm::Value *, Address, llvm::Type *) -DEFINE_BINARY_OPERATION(WeakTakeStrong, llvm::Value *, Address, llvm::Type *) -DEFINE_UNARY_OPERATION(WeakDestroy, void, Address) +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + DEFINE_BINARY_OPERATION(Name##CopyInit, void, Address, Address) \ + DEFINE_BINARY_OPERATION(Name##TakeInit, void, Address, Address) \ + DEFINE_BINARY_OPERATION(Name##CopyAssign, void, Address, Address) \ + DEFINE_BINARY_OPERATION(Name##TakeAssign, void, Address, Address) \ + DEFINE_BINARY_OPERATION(Name##Init, void, llvm::Value *, Address) \ + DEFINE_BINARY_OPERATION(Name##Assign, void, llvm::Value *, Address) \ + DEFINE_BINARY_OPERATION(Name##LoadStrong, llvm::Value *, Address,llvm::Type*)\ + DEFINE_BINARY_OPERATION(Name##TakeStrong, llvm::Value *, Address,llvm::Type*)\ + DEFINE_UNARY_OPERATION(Name##Destroy, void, Address) +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") +#include "swift/AST/ReferenceStorage.def" -DEFINE_BINARY_OPERATION(UnownedCopyInit, void, Address, Address) -DEFINE_BINARY_OPERATION(UnownedTakeInit, void, Address, Address) -DEFINE_BINARY_OPERATION(UnownedCopyAssign, void, Address, Address) -DEFINE_BINARY_OPERATION(UnownedTakeAssign, void, Address, Address) -DEFINE_BINARY_OPERATION(UnownedInit, void, llvm::Value *, Address) -DEFINE_BINARY_OPERATION(UnownedAssign, void, llvm::Value *, Address) -DEFINE_BINARY_OPERATION(UnownedLoadStrong, llvm::Value *, Address, llvm::Type *) -DEFINE_BINARY_OPERATION(UnownedTakeStrong, llvm::Value *, Address, llvm::Type *) -DEFINE_UNARY_OPERATION(UnownedDestroy, void, Address) #undef DEFINE_UNARY_OPERATION #undef DEFINE_BINARY_OPERATION -void IRGenFunction::emitUnownedRetain(llvm::Value *value, - ReferenceCounting style, - Atomicity atomicity) { - assert(style == ReferenceCounting::Native && - "only native references support scalar unowned reference-counting"); - emitNativeUnownedRetain(value, atomicity); -} - -void IRGenFunction::emitUnownedRelease(llvm::Value *value, - ReferenceCounting style, - Atomicity atomicity) { - assert(style == ReferenceCounting::Native && - "only native references support scalar unowned reference-counting"); - emitNativeUnownedRelease(value, atomicity); -} - -void IRGenFunction::emitStrongRetainUnowned(llvm::Value *value, - ReferenceCounting style, - Atomicity atomicity) { - assert(style == ReferenceCounting::Native && - "only native references support scalar unowned reference-counting"); - emitNativeStrongRetainUnowned(value, atomicity); -} - -void IRGenFunction::emitStrongRetainAndUnownedRelease(llvm::Value *value, - ReferenceCounting style, - Atomicity atomicity) { - assert(style == ReferenceCounting::Native && - "only native references support scalar unowned reference-counting"); - emitNativeStrongRetainAndUnownedRelease(value, atomicity); -} +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + void IRGenFunction::emit##Name##Retain(llvm::Value *value, \ + ReferenceCounting style, \ + Atomicity atomicity) { \ + assert(style == ReferenceCounting::Native && \ + "only native references support scalar reference-counting"); \ + emitNative##Name##Retain(value, atomicity); \ + } \ + void IRGenFunction::emit##Name##Release(llvm::Value *value, \ + ReferenceCounting style, \ + Atomicity atomicity) { \ + assert(style == ReferenceCounting::Native && \ + "only native references support scalar reference-counting"); \ + emitNative##Name##Release(value, atomicity); \ + } \ + void IRGenFunction::emitStrongRetain##Name(llvm::Value *value, \ + ReferenceCounting style, \ + Atomicity atomicity) { \ + assert(style == ReferenceCounting::Native && \ + "only native references support scalar reference-counting"); \ + emitNativeStrongRetain##Name(value, atomicity); \ + } \ + void IRGenFunction::emitStrongRetainAnd##Name##Release(llvm::Value *value, \ + ReferenceCounting style, \ + Atomicity atomicity) { \ + assert(style == ReferenceCounting::Native && \ + "only native references support scalar reference-counting"); \ + emitNativeStrongRetainAnd##Name##Release(value, atomicity); \ + } \ + void IRGenFunction::emitNative##Name##Init(llvm::Value *value, \ + Address dest) { \ + value = Builder.CreateBitCast(value, IGM.RefCountedPtrTy); \ + dest = Builder.CreateStructGEP(dest, 0, Size(0)); \ + Builder.CreateStore(value, dest); \ + emitNative##Name##Retain(value, getDefaultAtomicity()); \ + } \ + void IRGenFunction::emitNative##Name##Assign(llvm::Value *value, \ + Address dest) { \ + value = Builder.CreateBitCast(value, IGM.RefCountedPtrTy); \ + dest = Builder.CreateStructGEP(dest, 0, Size(0)); \ + auto oldValue = Builder.CreateLoad(dest); \ + Builder.CreateStore(value, dest); \ + emitNative##Name##Retain(value, getDefaultAtomicity()); \ + emitNative##Name##Release(oldValue, getDefaultAtomicity()); \ + } \ + llvm::Value *IRGenFunction::emitNative##Name##LoadStrong(Address src, \ + llvm::Type *type) { \ + src = Builder.CreateStructGEP(src, 0, Size(0)); \ + llvm::Value *value = Builder.CreateLoad(src); \ + value = Builder.CreateBitCast(value, type); \ + emitNativeStrongRetain##Name(value, getDefaultAtomicity()); \ + return value; \ + } \ + llvm::Value *IRGenFunction::emitNative##Name##TakeStrong(Address src, \ + llvm::Type *type) { \ + src = Builder.CreateStructGEP(src, 0, Size(0)); \ + llvm::Value *value = Builder.CreateLoad(src); \ + value = Builder.CreateBitCast(value, type); \ + emitNativeStrongRetainAnd##Name##Release(value, getDefaultAtomicity()); \ + return value; \ + } \ + void IRGenFunction::emitNative##Name##Destroy(Address ref) { \ + ref = Builder.CreateStructGEP(ref, 0, Size(0)); \ + llvm::Value *value = Builder.CreateLoad(ref); \ + emitNative##Name##Release(value, getDefaultAtomicity()); \ + } \ + void IRGenFunction::emitNative##Name##CopyInit(Address dest, Address src) { \ + src = Builder.CreateStructGEP(src, 0, Size(0)); \ + dest = Builder.CreateStructGEP(dest, 0, Size(0)); \ + llvm::Value *newValue = Builder.CreateLoad(src); \ + Builder.CreateStore(newValue, dest); \ + emitNative##Name##Retain(newValue, getDefaultAtomicity()); \ + } \ + void IRGenFunction::emitNative##Name##TakeInit(Address dest, Address src) { \ + src = Builder.CreateStructGEP(src, 0, Size(0)); \ + dest = Builder.CreateStructGEP(dest, 0, Size(0)); \ + llvm::Value *newValue = Builder.CreateLoad(src); \ + Builder.CreateStore(newValue, dest); \ + } \ + void IRGenFunction::emitNative##Name##CopyAssign(Address dest, Address src) { \ + src = Builder.CreateStructGEP(src, 0, Size(0)); \ + dest = Builder.CreateStructGEP(dest, 0, Size(0)); \ + llvm::Value *newValue = Builder.CreateLoad(src); \ + llvm::Value *oldValue = Builder.CreateLoad(dest); \ + Builder.CreateStore(newValue, dest); \ + emitNative##Name##Retain(newValue, getDefaultAtomicity()); \ + emitNative##Name##Release(oldValue, getDefaultAtomicity()); \ + } \ + void IRGenFunction::emitNative##Name##TakeAssign(Address dest, Address src) { \ + src = Builder.CreateStructGEP(src, 0, Size(0)); \ + dest = Builder.CreateStructGEP(dest, 0, Size(0)); \ + llvm::Value *newValue = Builder.CreateLoad(src); \ + llvm::Value *oldValue = Builder.CreateLoad(dest); \ + Builder.CreateStore(newValue, dest); \ + emitNative##Name##Release(oldValue, getDefaultAtomicity()); \ + } +#include "swift/AST/ReferenceStorage.def" /// Emit a release of a live value. void IRGenFunction::emitNativeStrongRelease(llvm::Value *value, @@ -1199,82 +1203,6 @@ void IRGenFunction::emitNativeSetDeallocating(llvm::Value *value) { emitUnaryRefCountCall(*this, IGM.getNativeSetDeallocatingFn(), value); } -void IRGenFunction::emitNativeUnownedInit(llvm::Value *value, - Address dest) { - value = Builder.CreateBitCast(value, IGM.RefCountedPtrTy); - dest = Builder.CreateStructGEP(dest, 0, Size(0)); - Builder.CreateStore(value, dest); - emitNativeUnownedRetain(value, getDefaultAtomicity()); -} - -void IRGenFunction::emitNativeUnownedAssign(llvm::Value *value, - Address dest) { - value = Builder.CreateBitCast(value, IGM.RefCountedPtrTy); - dest = Builder.CreateStructGEP(dest, 0, Size(0)); - auto oldValue = Builder.CreateLoad(dest); - Builder.CreateStore(value, dest); - emitNativeUnownedRetain(value, getDefaultAtomicity()); - emitNativeUnownedRelease(oldValue, getDefaultAtomicity()); -} - -llvm::Value *IRGenFunction::emitNativeUnownedLoadStrong(Address src, - llvm::Type *type) { - src = Builder.CreateStructGEP(src, 0, Size(0)); - llvm::Value *value = Builder.CreateLoad(src); - value = Builder.CreateBitCast(value, type); - emitNativeStrongRetainUnowned(value, getDefaultAtomicity()); - return value; -} - -llvm::Value *IRGenFunction::emitNativeUnownedTakeStrong(Address src, - llvm::Type *type) { - src = Builder.CreateStructGEP(src, 0, Size(0)); - llvm::Value *value = Builder.CreateLoad(src); - value = Builder.CreateBitCast(value, type); - emitNativeStrongRetainAndUnownedRelease(value, getDefaultAtomicity()); - return value; -} - -void IRGenFunction::emitNativeUnownedDestroy(Address ref) { - ref = Builder.CreateStructGEP(ref, 0, Size(0)); - llvm::Value *value = Builder.CreateLoad(ref); - emitNativeUnownedRelease(value, getDefaultAtomicity()); -} - -void IRGenFunction::emitNativeUnownedCopyInit(Address dest, Address src) { - src = Builder.CreateStructGEP(src, 0, Size(0)); - dest = Builder.CreateStructGEP(dest, 0, Size(0)); - llvm::Value *newValue = Builder.CreateLoad(src); - Builder.CreateStore(newValue, dest); - emitNativeUnownedRetain(newValue, getDefaultAtomicity()); -} - -void IRGenFunction::emitNativeUnownedTakeInit(Address dest, Address src) { - src = Builder.CreateStructGEP(src, 0, Size(0)); - dest = Builder.CreateStructGEP(dest, 0, Size(0)); - llvm::Value *newValue = Builder.CreateLoad(src); - Builder.CreateStore(newValue, dest); -} - -void IRGenFunction::emitNativeUnownedCopyAssign(Address dest, Address src) { - src = Builder.CreateStructGEP(src, 0, Size(0)); - dest = Builder.CreateStructGEP(dest, 0, Size(0)); - llvm::Value *newValue = Builder.CreateLoad(src); - llvm::Value *oldValue = Builder.CreateLoad(dest); - Builder.CreateStore(newValue, dest); - emitNativeUnownedRetain(newValue, getDefaultAtomicity()); - emitNativeUnownedRelease(oldValue, getDefaultAtomicity()); -} - -void IRGenFunction::emitNativeUnownedTakeAssign(Address dest, Address src) { - src = Builder.CreateStructGEP(src, 0, Size(0)); - dest = Builder.CreateStructGEP(dest, 0, Size(0)); - llvm::Value *newValue = Builder.CreateLoad(src); - llvm::Value *oldValue = Builder.CreateLoad(dest); - Builder.CreateStore(newValue, dest); - emitNativeUnownedRelease(oldValue, getDefaultAtomicity()); -} - llvm::Constant *IRGenModule::getFixLifetimeFn() { if (FixLifetimeFn) return FixLifetimeFn; @@ -1761,37 +1689,34 @@ void IRGenFunction::emit##ID(llvm::Value *value, Address src) { \ src.getAddress(), value); \ } -DEFINE_VALUE_OP(NativeStrongRetainUnowned) -DEFINE_VALUE_OP(NativeStrongRetainAndUnownedRelease) -DEFINE_VALUE_OP(NativeUnownedRelease) -DEFINE_VALUE_OP(NativeUnownedRetain) -DEFINE_LOAD_WEAK_OP(NativeWeakLoadStrong) -DEFINE_LOAD_WEAK_OP(NativeWeakTakeStrong) -DEFINE_STORE_WEAK_OP(NativeWeakInit) -DEFINE_STORE_WEAK_OP(NativeWeakAssign) -DEFINE_ADDR_OP(NativeWeakDestroy) -DEFINE_COPY_OP(NativeWeakCopyInit) -DEFINE_COPY_OP(NativeWeakCopyAssign) -DEFINE_COPY_OP(NativeWeakTakeInit) -DEFINE_COPY_OP(NativeWeakTakeAssign) -DEFINE_LOAD_WEAK_OP(UnknownUnownedLoadStrong) -DEFINE_LOAD_WEAK_OP(UnknownUnownedTakeStrong) -DEFINE_STORE_WEAK_OP(UnknownUnownedInit) -DEFINE_STORE_WEAK_OP(UnknownUnownedAssign) -DEFINE_ADDR_OP(UnknownUnownedDestroy) -DEFINE_COPY_OP(UnknownUnownedCopyInit) -DEFINE_COPY_OP(UnknownUnownedCopyAssign) -DEFINE_COPY_OP(UnknownUnownedTakeInit) -DEFINE_COPY_OP(UnknownUnownedTakeAssign) -DEFINE_LOAD_WEAK_OP(UnknownWeakLoadStrong) -DEFINE_LOAD_WEAK_OP(UnknownWeakTakeStrong) -DEFINE_STORE_WEAK_OP(UnknownWeakInit) -DEFINE_STORE_WEAK_OP(UnknownWeakAssign) -DEFINE_ADDR_OP(UnknownWeakDestroy) -DEFINE_COPY_OP(UnknownWeakCopyInit) -DEFINE_COPY_OP(UnknownWeakCopyAssign) -DEFINE_COPY_OP(UnknownWeakTakeInit) -DEFINE_COPY_OP(UnknownWeakTakeAssign) +#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Nativeness) \ + DEFINE_LOAD_WEAK_OP(Nativeness##Name##LoadStrong) \ + DEFINE_LOAD_WEAK_OP(Nativeness##Name##TakeStrong) \ + DEFINE_STORE_WEAK_OP(Nativeness##Name##Init) \ + DEFINE_STORE_WEAK_OP(Nativeness##Name##Assign) \ + DEFINE_ADDR_OP(Nativeness##Name##Destroy) \ + DEFINE_COPY_OP(Nativeness##Name##CopyInit) \ + DEFINE_COPY_OP(Nativeness##Name##CopyAssign) \ + DEFINE_COPY_OP(Nativeness##Name##TakeInit) \ + DEFINE_COPY_OP(Nativeness##Name##TakeAssign) +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Unknown) \ + NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Native) +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + DEFINE_VALUE_OP(NativeStrongRetain##Name) \ + DEFINE_VALUE_OP(NativeStrongRetainAnd##Name##Release) \ + DEFINE_VALUE_OP(Native##Name##Release) \ + DEFINE_VALUE_OP(Native##Name##Retain) +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Unknown) \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...") +#include "swift/AST/ReferenceStorage.def" +#undef DEFINE_VALUE_OP +#undef DEFINE_ADDR_OP +#undef DEFINE_COPY_OP +#undef DEFINE_LOAD_WEAK_OP +#undef DEFINE_STORE_WEAK_OP +#undef NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER llvm::Value *IRGenFunction::getLocalSelfMetadata() { assert(LocalSelf && "no local self metadata"); diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index c87c6180233..563c674a7d7 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -307,11 +307,12 @@ const TypeInfo &IRGenModule::getObjCClassPtrTypeInfo() { return Types.getObjCClassPtrTypeInfo(); } -const LoadableTypeInfo &TypeConverter::getObjCClassPtrTypeInfo() { +const TypeInfo &TypeConverter::getObjCClassPtrTypeInfo() { // ObjC class pointers look like unmanaged (untagged) object references. if (ObjCClassPtrTI) return *ObjCClassPtrTI; ObjCClassPtrTI = - createUnmanagedStorageType(IGM.ObjCClassPtrTy); + createUnmanagedStorageType(IGM.ObjCClassPtrTy, ReferenceCounting::ObjC, + /*isOptional*/false); ObjCClassPtrTI->NextConverted = FirstType; FirstType = ObjCClassPtrTI; return *ObjCClassPtrTI; diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index ffdadb8fca3..e8624d21bda 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -43,7 +43,6 @@ #include "ProtocolInfo.h" #include "ReferenceTypeInfo.h" #include "ScalarTypeInfo.h" -#include "WeakTypeInfo.h" #include "NativeConventionSchema.h" #include "IRGenMangler.h" #include "NonFixedTypeInfo.h" @@ -1158,10 +1157,11 @@ const TypeInfo &IRGenModule::getTypeMetadataPtrTypeInfo() { return Types.getTypeMetadataPtrTypeInfo(); } -const LoadableTypeInfo &TypeConverter::getTypeMetadataPtrTypeInfo() { +const TypeInfo &TypeConverter::getTypeMetadataPtrTypeInfo() { if (TypeMetadataPtrTI) return *TypeMetadataPtrTI; - TypeMetadataPtrTI = - createUnmanagedStorageType(IGM.TypeMetadataPtrTy); + TypeMetadataPtrTI = createUnmanagedStorageType(IGM.TypeMetadataPtrTy, + ReferenceCounting::Unknown, + /*isOptional*/false); TypeMetadataPtrTI->NextConverted = FirstType; FirstType = TypeMetadataPtrTI; return *TypeMetadataPtrTI; @@ -1668,12 +1668,10 @@ TypeCacheEntry TypeConverter::convertType(CanType ty) { case TypeKind::GenericTypeParam: case TypeKind::DependentMember: llvm_unreachable("can't convert dependent type"); - case TypeKind::UnmanagedStorage: - return convertUnmanagedStorageType(cast(ty)); - case TypeKind::UnownedStorage: - return convertUnownedStorageType(cast(ty)); - case TypeKind::WeakStorage: - return convertWeakStorageType(cast(ty)); +#define REF_STORAGE(Name, ...) \ + case TypeKind::Name##Storage: \ + return convert##Name##StorageType(cast(ty)); +#include "swift/AST/ReferenceStorage.def" case TypeKind::SILBlockStorage: { return convertBlockStorageType(cast(ty)); case TypeKind::SILBox: @@ -1695,42 +1693,22 @@ const TypeInfo *TypeConverter::convertInOutType(InOutType *T) { IGM.getPointerAlignment()); } -/// Convert an [unowned] storage type. The implementation here -/// depends on the underlying reference type. -const TypeInfo * -TypeConverter::convertUnownedStorageType(UnownedStorageType *refType) { - // The type may be optional. - CanType referent(refType->getReferentType()); - if (auto referentObj = referent.getOptionalObjectType()) - referent = referentObj; - assert(referent->allowsOwnership()); - auto &referentTI = cast(getCompleteTypeInfo(referent)); - return referentTI.createUnownedStorageType(*this); -} - -/// Convert an @unowned(unsafe) storage type. The implementation here -/// depends on the underlying reference type. -const TypeInfo * -TypeConverter::convertUnmanagedStorageType(UnmanagedStorageType *refType) { - // The type may be optional. - CanType referent(refType->getReferentType()); - if (auto referentObj = referent.getOptionalObjectType()) - referent = referentObj; - assert(referent->allowsOwnership()); - auto &referentTI = cast(getCompleteTypeInfo(referent)); - return referentTI.createUnmanagedStorageType(*this); -} - -/// Convert a weak storage type. The implementation here -/// depends on the underlying reference type. -const TypeInfo * -TypeConverter::convertWeakStorageType(WeakStorageType *refType) { - CanType referent = - CanType(refType->getReferentType()->getOptionalObjectType()); - assert(referent->allowsOwnership()); - auto &referentTI = cast(getCompleteTypeInfo(referent)); - return referentTI.createWeakStorageType(*this); +/// Convert a reference storage type. The implementation here depends on the +/// underlying reference type. The type may be optional. +#define REF_STORAGE(Name, ...) \ +const TypeInfo * \ +TypeConverter::convert##Name##StorageType(Name##StorageType *refType) { \ + CanType referent(refType->getReferentType()); \ + bool isOptional = false; \ + if (auto referentObj = referent.getOptionalObjectType()) { \ + referent = referentObj; \ + isOptional = true; \ + } \ + assert(referent->allowsOwnership()); \ + auto &referentTI = cast(getCompleteTypeInfo(referent)); \ + return referentTI.create##Name##StorageType(*this, isOptional); \ } +#include "swift/AST/ReferenceStorage.def" static void overwriteForwardDecl(llvm::DenseMap &cache, TypeBase *key, const TypeInfo *result) { @@ -1927,7 +1905,7 @@ const TypeInfo *TypeConverter::convertMetatypeType(MetatypeType *T) { return &getMetatypeTypeInfo(T->getRepresentation()); } -const LoadableTypeInfo & +const TypeInfo & TypeConverter::getMetatypeTypeInfo(MetatypeRepresentation representation) { switch (representation) { case MetatypeRepresentation::Thin: diff --git a/lib/IRGen/GenType.h b/lib/IRGen/GenType.h index 3b4f8d3615e..efd71d9775f 100644 --- a/lib/IRGen/GenType.h +++ b/lib/IRGen/GenType.h @@ -56,8 +56,6 @@ namespace irgen { class FixedTypeInfo; class LoadableTypeInfo; class TypeInfo; - class UnownedTypeInfo; - class WeakTypeInfo; /// Either a type or a forward-declaration. using TypeCacheEntry = llvm::PointerUnion; @@ -78,8 +76,8 @@ private: const LoadableTypeInfo *BridgeObjectTI = nullptr; const LoadableTypeInfo *RawPointerTI = nullptr; const LoadableTypeInfo *WitnessTablePtrTI = nullptr; - const LoadableTypeInfo *TypeMetadataPtrTI = nullptr; - const LoadableTypeInfo *ObjCClassPtrTI = nullptr; + const TypeInfo *TypeMetadataPtrTI = nullptr; + const TypeInfo *ObjCClassPtrTI = nullptr; const LoadableTypeInfo *EmptyTI = nullptr; const TypeInfo *AccessibleResilientStructTI = nullptr; @@ -125,9 +123,9 @@ private: const LoadableTypeInfo *convertBuiltinUnknownObject(); const LoadableTypeInfo *convertBuiltinBridgeObject(); const TypeInfo *convertResilientStruct(IsABIAccessible_t abiAccessible); - const TypeInfo *convertUnmanagedStorageType(UnmanagedStorageType *T); - const TypeInfo *convertUnownedStorageType(UnownedStorageType *T); - const TypeInfo *convertWeakStorageType(WeakStorageType *T); +#define REF_STORAGE(Name, ...) \ + const TypeInfo *convert##Name##StorageType(Name##StorageType *T); +#include "swift/AST/ReferenceStorage.def" public: TypeConverter(IRGenModule &IGM); @@ -143,21 +141,21 @@ public: const LoadableTypeInfo &getUnknownObjectTypeInfo(); const LoadableTypeInfo &getBridgeObjectTypeInfo(); const LoadableTypeInfo &getRawPointerTypeInfo(); - const LoadableTypeInfo &getTypeMetadataPtrTypeInfo(); - const LoadableTypeInfo &getObjCClassPtrTypeInfo(); + const TypeInfo &getTypeMetadataPtrTypeInfo(); + const TypeInfo &getObjCClassPtrTypeInfo(); const LoadableTypeInfo &getWitnessTablePtrTypeInfo(); const LoadableTypeInfo &getEmptyTypeInfo(); const TypeInfo &getResilientStructTypeInfo(IsABIAccessible_t abiAccessible); const ProtocolInfo &getProtocolInfo(ProtocolDecl *P); const LoadableTypeInfo &getOpaqueStorageTypeInfo(Size storageSize, Alignment storageAlign); - const LoadableTypeInfo &getMetatypeTypeInfo(MetatypeRepresentation representation); + const TypeInfo &getMetatypeTypeInfo(MetatypeRepresentation representation); - const WeakTypeInfo *createWeakStorageType(llvm::Type *valueType, - ReferenceCounting style); - const TypeInfo *createUnownedStorageType(llvm::Type *valueType, - ReferenceCounting style); - const LoadableTypeInfo *createUnmanagedStorageType(llvm::Type *valueType); +#define REF_STORAGE(Name, ...) \ + const TypeInfo *create##Name##StorageType(llvm::Type *valueType, \ + ReferenceCounting style, \ + bool isOptional); +#include "swift/AST/ReferenceStorage.def" /// Enter a generic context for lowering the parameters of a generic function /// type. diff --git a/lib/IRGen/HeapTypeInfo.h b/lib/IRGen/HeapTypeInfo.h index 94daebf56cf..718856fb23a 100644 --- a/lib/IRGen/HeapTypeInfo.h +++ b/lib/IRGen/HeapTypeInfo.h @@ -55,6 +55,11 @@ template class HeapTypeInfo : public SingleScalarTypeInfo { using super = SingleScalarTypeInfo; + llvm::Type *getOptionalIntType() const { + return llvm::IntegerType::get(this->getStorageType()->getContext(), + this->getFixedSize().getValueInBits()); + } + protected: using super::asDerived; public: @@ -117,59 +122,96 @@ public: asDerived().emitScalarRelease(IGF, value, atomicity); } - void strongRetainUnowned(IRGenFunction &IGF, Explosion &e, - Atomicity atomicity) const override { - llvm::Value *value = e.claimNext(); - IGF.emitStrongRetainUnowned(value, asDerived().getReferenceCounting(), - atomicity); +#define REF_STORAGE_HELPER(Name) \ + const TypeInfo * \ + create##Name##StorageType(TypeConverter &TC, \ + bool isOptional) const override { \ + return TC.create##Name##StorageType(this->getStorageType(), \ + asDerived().getReferenceCounting(), \ + isOptional); \ } - - void strongRetainUnownedRelease(IRGenFunction &IGF, - Explosion &e, - Atomicity atomicity) const override { - llvm::Value *value = e.claimNext(); - IGF.emitStrongRetainAndUnownedRelease(value, - asDerived().getReferenceCounting(), - atomicity); +#define NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + void name##LoadStrong(IRGenFunction &IGF, Address src, \ + Explosion &out, bool isOptional) const override { \ + llvm::Value *value = IGF.emit##Name##LoadStrong(src, \ + this->getStorageType(), \ + asDerived().getReferenceCounting()); \ + if (isOptional) { \ + out.add(IGF.Builder.CreatePtrToInt(value, getOptionalIntType())); \ + } else { \ + out.add(value); \ + } \ + } \ + void name##TakeStrong(IRGenFunction &IGF, Address src, \ + Explosion &out, bool isOptional) const override { \ + llvm::Value *value = IGF.emit##Name##TakeStrong(src, \ + this->getStorageType(), \ + asDerived().getReferenceCounting()); \ + if (isOptional) { \ + out.add(IGF.Builder.CreatePtrToInt(value, getOptionalIntType())); \ + } else { \ + out.add(value); \ + } \ + } \ + void name##Init(IRGenFunction &IGF, Explosion &in, \ + Address dest, bool isOptional) const override { \ + llvm::Value *value = in.claimNext(); \ + if (isOptional) { \ + assert(value->getType() == getOptionalIntType()); \ + value = IGF.Builder.CreateIntToPtr(value, this->getStorageType()); \ + } \ + IGF.emit##Name##Init(value, dest, asDerived().getReferenceCounting()); \ + } \ + void name##Assign(IRGenFunction &IGF, Explosion &in, \ + Address dest, bool isOptional) const override { \ + llvm::Value *value = in.claimNext(); \ + if (isOptional) { \ + assert(value->getType() == getOptionalIntType()); \ + value = IGF.Builder.CreateIntToPtr(value, this->getStorageType()); \ + } \ + IGF.emit##Name##Assign(value, dest, asDerived().getReferenceCounting()); \ } - - void unownedRetain(IRGenFunction &IGF, Explosion &e, - Atomicity atomicity) const override { - llvm::Value *value = e.claimNext(); - IGF.emitUnownedRetain(value, asDerived().getReferenceCounting(), atomicity); - } - - void unownedRelease(IRGenFunction &IGF, Explosion &e, - Atomicity atomicity) const override { - llvm::Value *value = e.claimNext(); - IGF.emitUnownedRelease(value, asDerived().getReferenceCounting(), atomicity); - } - - void unownedLoadStrong(IRGenFunction &IGF, Address src, - Explosion &out) const override { - llvm::Value *value = IGF.emitUnownedLoadStrong(src, this->getStorageType(), - asDerived().getReferenceCounting()); - out.add(value); - } - - void unownedTakeStrong(IRGenFunction &IGF, Address src, - Explosion &out) const override { - llvm::Value *value = IGF.emitUnownedTakeStrong(src, this->getStorageType(), - asDerived().getReferenceCounting()); - out.add(value); - } - - void unownedInit(IRGenFunction &IGF, Explosion &in, - Address dest) const override { - IGF.emitUnownedInit(in.claimNext(), dest, - asDerived().getReferenceCounting()); - } - - void unownedAssign(IRGenFunction &IGF, Explosion &in, - Address dest) const override { - IGF.emitUnownedAssign(in.claimNext(), dest, - asDerived().getReferenceCounting()); +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + void strongRetain##Name(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + llvm::Value *value = e.claimNext(); \ + assert(asDerived().getReferenceCounting() == ReferenceCounting::Native); \ + IGF.emitNativeStrongRetain##Name(value, atomicity); \ + } \ + void strongRetain##Name##Release(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + llvm::Value *value = e.claimNext(); \ + assert(asDerived().getReferenceCounting() == ReferenceCounting::Native); \ + IGF.emitNativeStrongRetainAnd##Name##Release(value, atomicity); \ + } \ + void name##Retain(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + llvm::Value *value = e.claimNext(); \ + assert(asDerived().getReferenceCounting() == ReferenceCounting::Native); \ + IGF.emitNative##Name##Retain(value, atomicity); \ + } \ + void name##Release(IRGenFunction &IGF, Explosion &e, \ + Atomicity atomicity) const override { \ + llvm::Value *value = e.claimNext(); \ + assert(asDerived().getReferenceCounting() == ReferenceCounting::Native); \ + IGF.emitNative##Name##Release(value, atomicity); \ } +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + REF_STORAGE_HELPER(Name) +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + REF_STORAGE_HELPER(Name) +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + REF_STORAGE_HELPER(Name) +#define UNCHECKED_REF_STORAGE(Name, ...) \ + REF_STORAGE_HELPER(Name) +#include "swift/AST/ReferenceStorage.def" +#undef REF_STORAGE_HELPER +#undef NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER +#undef ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER LoadedRef loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc, Address addr) const override { @@ -178,22 +220,6 @@ public: return LoadedRef(ptr, true); } - const WeakTypeInfo *createWeakStorageType(TypeConverter &TC) const override { - return TC.createWeakStorageType(this->getStorageType(), - asDerived().getReferenceCounting()); - } - - const TypeInfo * - createUnownedStorageType(TypeConverter &TC) const override { - return TC.createUnownedStorageType(this->getStorageType(), - asDerived().getReferenceCounting()); - } - - const TypeInfo *createUnmanagedStorageType(TypeConverter &TC) const override { - return TC.createUnmanagedStorageType(this->getStorageType()); - } - - // Extra inhabitants of heap object pointers. bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index 32c1861ef2c..8183281c384 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1270,9 +1270,10 @@ private: } // Reference storage types. - case TypeKind::UnownedStorage: - case TypeKind::UnmanagedStorage: - case TypeKind::WeakStorage: { +#define REF_STORAGE(Name, ...) \ + case TypeKind::Name##Storage: +#include "swift/AST/ReferenceStorage.def" + { auto *ReferenceTy = cast(BaseTy); auto CanTy = ReferenceTy->getReferentType(); auto L = getDebugLoc(*this, DbgTy.getDecl()); diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h index 7324308bc70..e5beb6829a3 100644 --- a/lib/IRGen/IRGenFunction.h +++ b/lib/IRGen/IRGenFunction.h @@ -314,53 +314,90 @@ public: Atomicity atomicity); llvm::Value *emitLoadRefcountedPtr(Address addr, ReferenceCounting style); - // - unowned references - void emitUnownedRetain(llvm::Value *value, ReferenceCounting style, - Atomicity atomicity); - void emitUnownedRelease(llvm::Value *value, ReferenceCounting style, - Atomicity atomicity); - void emitStrongRetainUnowned(llvm::Value *value, ReferenceCounting style, - Atomicity atomicity); - void emitStrongRetainAndUnownedRelease(llvm::Value *value, - ReferenceCounting style, - Atomicity atomicity); - void emitUnownedInit(llvm::Value *val, Address dest, ReferenceCounting style); - void emitUnownedAssign(llvm::Value *value, Address dest, - ReferenceCounting style); - void emitUnownedCopyInit(Address destAddr, Address srcAddr, - ReferenceCounting style); - void emitUnownedTakeInit(Address destAddr, Address srcAddr, - ReferenceCounting style); - void emitUnownedCopyAssign(Address destAddr, Address srcAddr, - ReferenceCounting style); - void emitUnownedTakeAssign(Address destAddr, Address srcAddr, - ReferenceCounting style); - llvm::Value *emitUnownedLoadStrong(Address src, llvm::Type *resultType, - ReferenceCounting style); - llvm::Value *emitUnownedTakeStrong(Address src, llvm::Type *resultType, - ReferenceCounting style); - void emitUnownedDestroy(Address addr, ReferenceCounting style); - llvm::Value *getUnownedExtraInhabitantIndex(Address src, - ReferenceCounting style); - void storeUnownedExtraInhabitant(llvm::Value *index, Address dest, - ReferenceCounting style); + llvm::Value *getReferenceStorageExtraInhabitantIndex(Address src, + ReferenceOwnership ownership, + ReferenceCounting style); + void storeReferenceStorageExtraInhabitant(llvm::Value *index, + Address dest, + ReferenceOwnership ownership, + ReferenceCounting style); - // - weak references - void emitWeakInit(llvm::Value *ref, Address dest, ReferenceCounting style); - void emitWeakAssign(llvm::Value *ref, Address dest, ReferenceCounting style); - void emitWeakCopyInit(Address destAddr, Address srcAddr, - ReferenceCounting style); - void emitWeakTakeInit(Address destAddr, Address srcAddr, - ReferenceCounting style); - void emitWeakCopyAssign(Address destAddr, Address srcAddr, - ReferenceCounting style); - void emitWeakTakeAssign(Address destAddr, Address srcAddr, - ReferenceCounting style); - llvm::Value *emitWeakLoadStrong(Address src, llvm::Type *resultType, - ReferenceCounting style); - llvm::Value *emitWeakTakeStrong(Address src, llvm::Type *resultType, - ReferenceCounting style); - void emitWeakDestroy(Address addr, ReferenceCounting style); +#define NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Kind) \ + void emit##Kind##Name##Init(llvm::Value *val, Address dest); \ + void emit##Kind##Name##Assign(llvm::Value *value, Address dest); \ + void emit##Kind##Name##CopyInit(Address destAddr, Address srcAddr); \ + void emit##Kind##Name##TakeInit(Address destAddr, Address srcAddr); \ + void emit##Kind##Name##CopyAssign(Address destAddr, Address srcAddr); \ + void emit##Kind##Name##TakeAssign(Address destAddr, Address srcAddr); \ + llvm::Value *emit##Kind##Name##LoadStrong(Address src, \ + llvm::Type *resultType); \ + llvm::Value *emit##Kind##Name##TakeStrong(Address src, \ + llvm::Type *resultType); \ + void emit##Kind##Name##Destroy(Address addr); +#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Kind) \ + void emit##Kind##Name##Retain(llvm::Value *value, Atomicity atomicity); \ + void emit##Kind##Name##Release(llvm::Value *value, Atomicity atomicity); \ + void emit##Kind##StrongRetain##Name(llvm::Value *value, Atomicity atomicity);\ + void emit##Kind##StrongRetainAnd##Name##Release(llvm::Value *value, \ + Atomicity atomicity); +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Native) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Unknown) \ + void emit##Name##Init(llvm::Value *val, Address dest, ReferenceCounting style); \ + void emit##Name##Assign(llvm::Value *value, Address dest, \ + ReferenceCounting style); \ + void emit##Name##CopyInit(Address destAddr, Address srcAddr, \ + ReferenceCounting style); \ + void emit##Name##TakeInit(Address destAddr, Address srcAddr, \ + ReferenceCounting style); \ + void emit##Name##CopyAssign(Address destAddr, Address srcAddr, \ + ReferenceCounting style); \ + void emit##Name##TakeAssign(Address destAddr, Address srcAddr, \ + ReferenceCounting style); \ + llvm::Value *emit##Name##LoadStrong(Address src, llvm::Type *resultType, \ + ReferenceCounting style); \ + llvm::Value *emit##Name##TakeStrong(Address src, llvm::Type *resultType, \ + ReferenceCounting style); \ + void emit##Name##Destroy(Address addr, ReferenceCounting style); +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") \ + ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Native) \ + ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Unknown) \ + void emit##Name##Retain(llvm::Value *value, ReferenceCounting style, \ + Atomicity atomicity); \ + void emit##Name##Release(llvm::Value *value, ReferenceCounting style, \ + Atomicity atomicity); \ + void emitStrongRetain##Name(llvm::Value *value, ReferenceCounting style, \ + Atomicity atomicity); \ + void emitStrongRetainAnd##Name##Release(llvm::Value *value, \ + ReferenceCounting style, \ + Atomicity atomicity); +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Native) \ + void emit##Name##Retain(llvm::Value *value, ReferenceCounting style, \ + Atomicity atomicity) { \ + assert(style == ReferenceCounting::Native); \ + emitNative##Name##Retain(value, atomicity); \ + } \ + void emit##Name##Release(llvm::Value *value, ReferenceCounting style, \ + Atomicity atomicity) { \ + assert(style == ReferenceCounting::Native); \ + emitNative##Name##Release(value, atomicity); \ + } \ + void emitStrongRetain##Name(llvm::Value *value, ReferenceCounting style, \ + Atomicity atomicity) { \ + assert(style == ReferenceCounting::Native); \ + emitNativeStrongRetain##Name(value, atomicity); \ + } \ + void emitStrongRetainAnd##Name##Release(llvm::Value *value, \ + ReferenceCounting style, \ + Atomicity atomicity) { \ + assert(style == ReferenceCounting::Native); \ + emitNativeStrongRetainAnd##Name##Release(value, atomicity); \ + } +#include "swift/AST/ReferenceStorage.def" +#undef NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER +#undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER // Routines for the Swift native reference-counting style. // - strong references @@ -369,32 +406,7 @@ public: void emitNativeStrongRetain(llvm::Value *value, Atomicity atomicity); void emitNativeStrongRelease(llvm::Value *value, Atomicity atomicity); void emitNativeSetDeallocating(llvm::Value *value); - // - unowned references - void emitNativeUnownedRetain(llvm::Value *value, Atomicity atomicity); - void emitNativeUnownedRelease(llvm::Value *value, Atomicity atomicity); - void emitNativeStrongRetainUnowned(llvm::Value *value, Atomicity atomicity); - void emitNativeStrongRetainAndUnownedRelease(llvm::Value *value, - Atomicity atomicity); - void emitNativeUnownedInit(llvm::Value *val, Address dest); - void emitNativeUnownedAssign(llvm::Value *value, Address dest); - void emitNativeUnownedCopyInit(Address destAddr, Address srcAddr); - void emitNativeUnownedTakeInit(Address destAddr, Address srcAddr); - void emitNativeUnownedCopyAssign(Address destAddr, Address srcAddr); - void emitNativeUnownedTakeAssign(Address destAddr, Address srcAddr); - llvm::Value *emitNativeUnownedLoadStrong(Address src, llvm::Type *resultType); - llvm::Value *emitNativeUnownedTakeStrong(Address src, llvm::Type *resultType); - void emitNativeUnownedDestroy(Address addr); - // - weak references - void emitNativeWeakInit(llvm::Value *value, Address dest); - void emitNativeWeakAssign(llvm::Value *value, Address dest); - llvm::Value *emitNativeWeakLoadStrong(Address src, llvm::Type *type); - llvm::Value *emitNativeWeakTakeStrong(Address src, llvm::Type *type); - void emitNativeWeakDestroy(Address addr); - void emitNativeWeakCopyInit(Address destAddr, Address srcAddr); - void emitNativeWeakTakeInit(Address destAddr, Address srcAddr); - void emitNativeWeakCopyAssign(Address destAddr, Address srcAddr); - void emitNativeWeakTakeAssign(Address destAddr, Address srcAddr); // - other operations llvm::Value *emitNativeTryPin(llvm::Value *object, Atomicity atomicity); void emitNativeUnpin(llvm::Value *handle, Atomicity atomicity); @@ -413,26 +425,6 @@ public: // - strong references void emitUnknownStrongRetain(llvm::Value *value, Atomicity atomicity); void emitUnknownStrongRelease(llvm::Value *value, Atomicity atomicity); - // - unowned references - void emitUnknownUnownedInit(llvm::Value *val, Address dest); - void emitUnknownUnownedAssign(llvm::Value *value, Address dest); - void emitUnknownUnownedCopyInit(Address destAddr, Address srcAddr); - void emitUnknownUnownedTakeInit(Address destAddr, Address srcAddr); - void emitUnknownUnownedCopyAssign(Address destAddr, Address srcAddr); - void emitUnknownUnownedTakeAssign(Address destAddr, Address srcAddr); - llvm::Value *emitUnknownUnownedLoadStrong(Address src, llvm::Type *resultTy); - llvm::Value *emitUnknownUnownedTakeStrong(Address src, llvm::Type *resultTy); - void emitUnknownUnownedDestroy(Address addr); - // - weak references - void emitUnknownWeakDestroy(Address addr); - void emitUnknownWeakCopyInit(Address destAddr, Address srcAddr); - void emitUnknownWeakTakeInit(Address destAddr, Address srcAddr); - void emitUnknownWeakCopyAssign(Address destAddr, Address srcAddr); - void emitUnknownWeakTakeAssign(Address destAddr, Address srcAddr); - void emitUnknownWeakInit(llvm::Value *value, Address dest); - void emitUnknownWeakAssign(llvm::Value *value, Address dest); - llvm::Value *emitUnknownWeakLoadStrong(Address src, llvm::Type *type); - llvm::Value *emitUnknownWeakTakeStrong(Address src, llvm::Type *type); // Routines for the Builtin.NativeObject reference-counting style. void emitBridgeStrongRetain(llvm::Value *value, Atomicity atomicity); diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 7dd39478f9f..7c70497bed4 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -179,13 +179,11 @@ IRGenModule::IRGenModule(IRGenerator &irgen, RefCountedPtrTy = RefCountedStructTy->getPointerTo(/*addrspace*/ 0); RefCountedNull = llvm::ConstantPointerNull::get(RefCountedPtrTy); - // For now, native weak references are just a pointer. - WeakReferencePtrTy = - createStructPointerType(*this, "swift.weak", { RefCountedPtrTy }); - - // Native unowned references are just a pointer. - UnownedReferencePtrTy = - createStructPointerType(*this, "swift.unowned", { RefCountedPtrTy }); + // For now, references storage types are just pointers. +#define CHECKED_REF_STORAGE(Name, name, ...) \ + Name##ReferencePtrTy = \ + createStructPointerType(*this, "swift." #name, { RefCountedPtrTy }); +#include "swift/AST/ReferenceStorage.def" // A type metadata record is the structure pointed to by the canonical // address point of a type metadata. This is at least one word, and diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 90aaaa5620b..6d762137154 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -517,8 +517,9 @@ public: llvm::StructType *RefCountedStructTy;/// %swift.refcounted = type { ... } Size RefCountedStructSize; /// sizeof(%swift.refcounted) llvm::PointerType *RefCountedPtrTy; /// %swift.refcounted* - llvm::PointerType *WeakReferencePtrTy;/// %swift.weak_reference* - llvm::PointerType *UnownedReferencePtrTy;/// %swift.unowned_reference* +#define CHECKED_REF_STORAGE(Name, ...) \ + llvm::PointerType *Name##ReferencePtrTy; /// %swift. #name _reference* +#include "swift/AST/ReferenceStorage.def" llvm::Constant *RefCountedNull; /// %swift.refcounted* null llvm::StructType *FunctionPairTy; /// { i8*, %swift.refcounted* } llvm::StructType *NoEscapeFunctionPairTy; /// { i8*, %swift.opaque* } @@ -623,7 +624,7 @@ public: llvm::Type *getReferenceType(ReferenceCounting style); - static bool isUnownedReferenceAddressOnly(ReferenceCounting style) { + static bool isLoadableReferenceAddressOnly(ReferenceCounting style) { switch (style) { case ReferenceCounting::Native: return false; @@ -635,7 +636,7 @@ public: case ReferenceCounting::Bridge: case ReferenceCounting::Error: - llvm_unreachable("unowned references to this type are not supported"); + llvm_unreachable("loadable references to this type are not supported"); } llvm_unreachable("Not a valid ReferenceCounting."); @@ -648,15 +649,16 @@ public: const SpareBitVector &getFunctionPointerSpareBits() const; const SpareBitVector &getWitnessTablePtrSpareBits() const; - SpareBitVector getWeakReferenceSpareBits() const; - Size getWeakReferenceSize() const { return PtrSize; } - Alignment getWeakReferenceAlignment() const { return getPointerAlignment(); } - - SpareBitVector getUnownedReferenceSpareBits(ReferenceCounting style) const; - unsigned getUnownedExtraInhabitantCount(ReferenceCounting style); - APInt getUnownedExtraInhabitantValue(unsigned bits, unsigned index, - ReferenceCounting style); - APInt getUnownedExtraInhabitantMask(ReferenceCounting style); + /// Return runtime specific extra inhabitant and spare bits policies. + unsigned getReferenceStorageExtraInhabitantCount(ReferenceOwnership ownership, + ReferenceCounting style) const; + SpareBitVector getReferenceStorageSpareBits(ReferenceOwnership ownership, + ReferenceCounting style) const; + APInt getReferenceStorageExtraInhabitantValue(unsigned bits, unsigned index, + ReferenceOwnership ownership, + ReferenceCounting style) const; + APInt getReferenceStorageExtraInhabitantMask(ReferenceOwnership ownership, + ReferenceCounting style) const; llvm::Type *getFixedBufferTy(); llvm::Type *getValueWitnessTy(ValueWitness index); diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 4553214d74b..ecf062b8b96 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -75,7 +75,6 @@ #include "MetadataRequest.h" #include "NativeConventionSchema.h" #include "ReferenceTypeInfo.h" -#include "WeakTypeInfo.h" using namespace swift; using namespace irgen; @@ -960,12 +959,9 @@ public: } void visitDebugValueInst(DebugValueInst *i); void visitDebugValueAddrInst(DebugValueAddrInst *i); - void visitLoadWeakInst(LoadWeakInst *i); - void visitStoreWeakInst(StoreWeakInst *i); void visitRetainValueInst(RetainValueInst *i); void visitRetainValueAddrInst(RetainValueAddrInst *i); void visitCopyValueInst(CopyValueInst *i); - void visitCopyUnownedValueInst(CopyUnownedValueInst *i); void visitReleaseValueInst(ReleaseValueInst *i); void visitReleaseValueAddrInst(ReleaseValueAddrInst *i); void visitDestroyValueInst(DestroyValueInst *i); @@ -1073,11 +1069,6 @@ public: void visitStrongUnpinInst(StrongUnpinInst *i); void visitStrongRetainInst(StrongRetainInst *i); void visitStrongReleaseInst(StrongReleaseInst *i); - void visitStrongRetainUnownedInst(StrongRetainUnownedInst *i); - void visitUnownedRetainInst(UnownedRetainInst *i); - void visitUnownedReleaseInst(UnownedReleaseInst *i); - void visitLoadUnownedInst(LoadUnownedInst *i); - void visitStoreUnownedInst(StoreUnownedInst *i); void visitIsUniqueInst(IsUniqueInst *i); void visitIsUniqueOrPinnedInst(IsUniqueOrPinnedInst *i); void visitIsEscapingClosureInst(IsEscapingClosureInst *i); @@ -1107,10 +1098,6 @@ public: void visitUncheckedBitwiseCastInst(UncheckedBitwiseCastInst *i); void visitRefToRawPointerInst(RefToRawPointerInst *i); void visitRawPointerToRefInst(RawPointerToRefInst *i); - void visitRefToUnownedInst(RefToUnownedInst *i); - void visitUnownedToRefInst(UnownedToRefInst *i); - void visitRefToUnmanagedInst(RefToUnmanagedInst *i); - void visitUnmanagedToRefInst(UnmanagedToRefInst *i); void visitThinToThickFunctionInst(ThinToThickFunctionInst *i); void visitThickToObjCMetatypeInst(ThickToObjCMetatypeInst *i); void visitObjCToThickMetatypeInst(ObjCToThickMetatypeInst *i); @@ -1152,6 +1139,27 @@ public: void visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *i); void visitKeyPathInst(KeyPathInst *I); + + +#define LOADABLE_REF_STORAGE_HELPER(Name) \ + void visitRefTo##Name##Inst(RefTo##Name##Inst *i); \ + void visit##Name##ToRefInst(Name##ToRefInst *i); +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + void visitLoad##Name##Inst(Load##Name##Inst *i); \ + void visitStore##Name##Inst(Store##Name##Inst *i); +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + LOADABLE_REF_STORAGE_HELPER(Name) \ + void visitStrongRetain##Name##Inst(StrongRetain##Name##Inst *i); \ + void visit##Name##RetainInst(Name##RetainInst *i); \ + void visit##Name##ReleaseInst(Name##ReleaseInst *i); \ + void visitCopy##Name##ValueInst(Copy##Name##ValueInst *i); +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...") +#define UNCHECKED_REF_STORAGE(Name, ...) \ + LOADABLE_REF_STORAGE_HELPER(Name) +#include "swift/AST/ReferenceStorage.def" +#undef LOADABLE_REF_STORAGE_HELPER }; } // end anonymous namespace @@ -3741,32 +3749,6 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) { : IndirectValue); } -void IRGenSILFunction::visitLoadWeakInst(swift::LoadWeakInst *i) { - Address source = getLoweredAddress(i->getOperand()); - auto &weakTI = cast(getTypeInfo(i->getOperand()->getType())); - - Explosion result; - if (i->isTake()) { - weakTI.weakTakeStrong(*this, source, result); - } else { - weakTI.weakLoadStrong(*this, source, result); - } - - setLoweredExplosion(i, result); -} - -void IRGenSILFunction::visitStoreWeakInst(swift::StoreWeakInst *i) { - Explosion source = getLoweredExplosion(i->getSrc()); - Address dest = getLoweredAddress(i->getDest()); - - auto &weakTI = cast(getTypeInfo(i->getDest()->getType())); - if (i->isInitializationOfDest()) { - weakTI.weakInit(*this, source, dest); - } else { - weakTI.weakAssign(*this, source, dest); - } -} - void IRGenSILFunction::visitFixLifetimeInst(swift::FixLifetimeInst *i) { if (i->getOperand()->getType().isAddress()) { // Just pass in the address to fix lifetime if we have one. We will not do @@ -3840,68 +3822,79 @@ void IRGenSILFunction::visitStrongReleaseInst(swift::StrongReleaseInst *i) { static const ReferenceTypeInfo &getReferentTypeInfo(IRGenFunction &IGF, SILType silType) { auto type = silType.castTo().getReferentType(); + if (auto ty = type->getOptionalObjectType()) + type = ty->getCanonicalType(); return cast(IGF.getTypeInfoForLowered(type)); } -void IRGenSILFunction:: -visitStrongRetainUnownedInst(swift::StrongRetainUnownedInst *i) { - Explosion lowered = getLoweredExplosion(i->getOperand()); - auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); - ti.strongRetainUnowned(*this, lowered, i->isAtomic() ? irgen::Atomicity::Atomic - : irgen::Atomicity::NonAtomic); -} - -void IRGenSILFunction::visitCopyUnownedValueInst( - swift::CopyUnownedValueInst *i) { - Explosion in = getLoweredExplosion(i->getOperand()); - auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); - ti.strongRetainUnowned(*this, in, irgen::Atomicity::Atomic); - // Semantically we are just passing through the input parameter but as a - // strong reference... at LLVM IR level these type differences don't - // matter. So just set the lowered explosion appropriately. - Explosion output = getLoweredExplosion(i->getOperand()); - setLoweredExplosion(i, output); -} - -void IRGenSILFunction::visitUnownedRetainInst(swift::UnownedRetainInst *i) { - Explosion lowered = getLoweredExplosion(i->getOperand()); - auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); - ti.unownedRetain(*this, lowered, i->isAtomic() ? irgen::Atomicity::Atomic - : irgen::Atomicity::NonAtomic); -} - -void IRGenSILFunction::visitUnownedReleaseInst(swift::UnownedReleaseInst *i) { - Explosion lowered = getLoweredExplosion(i->getOperand()); - auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); - ti.unownedRelease(*this, lowered, i->isAtomic() ? irgen::Atomicity::Atomic - : irgen::Atomicity::NonAtomic); -} - -void IRGenSILFunction::visitLoadUnownedInst(swift::LoadUnownedInst *i) { - Address source = getLoweredAddress(i->getOperand()); - auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); - - Explosion result; - if (i->isTake()) { - ti.unownedTakeStrong(*this, source, result); - } else { - ti.unownedLoadStrong(*this, source, result); +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + void IRGenSILFunction::visitLoad##Name##Inst(swift::Load##Name##Inst *i) { \ + Address source = getLoweredAddress(i->getOperand()); \ + auto silTy = i->getOperand()->getType(); \ + auto ty = cast(silTy.getASTType()); \ + auto isOptional = bool(ty.getReferentType()->getOptionalObjectType()); \ + auto &ti = getReferentTypeInfo(*this, silTy); \ + Explosion result; \ + if (i->isTake()) { \ + ti.name##TakeStrong(*this, source, result, isOptional); \ + } else { \ + ti.name##LoadStrong(*this, source, result, isOptional); \ + } \ + setLoweredExplosion(i, result); \ + } \ + void IRGenSILFunction::visitStore##Name##Inst(swift::Store##Name##Inst *i) { \ + Explosion source = getLoweredExplosion(i->getSrc()); \ + Address dest = getLoweredAddress(i->getDest()); \ + auto silTy = i->getDest()->getType(); \ + auto ty = cast(silTy.getASTType()); \ + auto isOptional = bool(ty.getReferentType()->getOptionalObjectType()); \ + auto &ti = getReferentTypeInfo(*this, silTy); \ + if (i->isInitializationOfDest()) { \ + ti.name##Init(*this, source, dest, isOptional); \ + } else { \ + ti.name##Assign(*this, source, dest, isOptional); \ + } \ } - - setLoweredExplosion(i, result); -} - -void IRGenSILFunction::visitStoreUnownedInst(swift::StoreUnownedInst *i) { - Explosion source = getLoweredExplosion(i->getSrc()); - Address dest = getLoweredAddress(i->getDest()); - - auto &ti = getReferentTypeInfo(*this, i->getDest()->getType()); - if (i->isInitializationOfDest()) { - ti.unownedInit(*this, source, dest); - } else { - ti.unownedAssign(*this, source, dest); +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + void IRGenSILFunction:: \ + visitStrongRetain##Name##Inst(swift::StrongRetain##Name##Inst *i) { \ + Explosion lowered = getLoweredExplosion(i->getOperand()); \ + auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); \ + ti.strongRetain##Name(*this, lowered, \ + i->isAtomic() ? irgen::Atomicity::Atomic \ + : irgen::Atomicity::NonAtomic); \ + } \ + void IRGenSILFunction::visit##Name##RetainInst(swift::Name##RetainInst *i) { \ + Explosion lowered = getLoweredExplosion(i->getOperand()); \ + auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); \ + ti.name##Retain(*this, lowered, \ + i->isAtomic() ? irgen::Atomicity::Atomic \ + : irgen::Atomicity::NonAtomic); \ + } \ + void \ + IRGenSILFunction::visit##Name##ReleaseInst(swift::Name##ReleaseInst *i) { \ + Explosion lowered = getLoweredExplosion(i->getOperand()); \ + auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); \ + ti.name##Release(*this, lowered, \ + i->isAtomic() ? irgen::Atomicity::Atomic \ + : irgen::Atomicity::NonAtomic); \ + } \ + void IRGenSILFunction::visitCopy##Name##ValueInst( \ + swift::Copy##Name##ValueInst *i) { \ + Explosion in = getLoweredExplosion(i->getOperand()); \ + auto &ti = getReferentTypeInfo(*this, i->getOperand()->getType()); \ + ti.strongRetain##Name(*this, in, irgen::Atomicity::Atomic); \ + /* Semantically we are just passing through the input parameter but as a */\ + /* strong reference... at LLVM IR level these type differences don't */ \ + /* matter. So just set the lowered explosion appropriately. */ \ + Explosion output = getLoweredExplosion(i->getOperand()); \ + setLoweredExplosion(i, output); \ } -} +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") +#include "swift/AST/ReferenceStorage.def" +#undef COMMON_CHECKED_REF_STORAGE static bool hasReferenceSemantics(IRGenSILFunction &IGF, SILType silType) { @@ -4725,10 +4718,10 @@ static void trivialRefConversion(IRGenSILFunction &IGF, void IRGenSILFunction::visit##KIND##Inst(swift::KIND##Inst *i) { \ ::trivialRefConversion(*this, i->getOperand(), i); \ } -NOOP_CONVERSION(UnownedToRef) -NOOP_CONVERSION(RefToUnowned) -NOOP_CONVERSION(UnmanagedToRef) -NOOP_CONVERSION(RefToUnmanaged) +#define LOADABLE_REF_STORAGE(Name, ...) \ + NOOP_CONVERSION(Name##ToRef) \ + NOOP_CONVERSION(RefTo##Name) +#include "swift/AST/ReferenceStorage.def" #undef NOOP_CONVERSION void IRGenSILFunction::visitThinToThickFunctionInst( diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 4769372db2e..c18a70718db 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -2255,23 +2255,15 @@ namespace { // object. auto &C = IGF.IGM.Context; - CanType referent; - switch (type->getOwnership()) { - case ReferenceOwnership::Strong: - llvm_unreachable("shouldn't be a ReferenceStorageType"); - case ReferenceOwnership::Weak: - referent = type.getReferentType().getOptionalObjectType(); - break; - case ReferenceOwnership::Unmanaged: - case ReferenceOwnership::Unowned: - referent = type.getReferentType(); - break; - } + CanType referent = type.getReferentType(); + CanType underlyingTy = referent; + if (auto Ty = referent.getOptionalObjectType()) + underlyingTy = Ty; // Reference storage types with witness tables need open-coded layouts. // TODO: Maybe we could provide prefabs for 1 witness table. - if (referent.isExistentialType()) { - auto layout = referent.getExistentialLayout(); + if (underlyingTy.isExistentialType()) { + auto layout = underlyingTy.getExistentialLayout(); for (auto *protoTy : layout.getProtocols()) { auto *protoDecl = protoTy->getDecl(); if (IGF.getSILTypes().protocolRequiresWitnessTable(protoDecl)) @@ -2290,7 +2282,7 @@ namespace { } CanType valueWitnessReferent; - switch (getReferenceCountingForType(IGF.IGM, referent)) { + switch (getReferenceCountingForType(IGF.IGM, underlyingTy)) { case ReferenceCounting::Unknown: case ReferenceCounting::Block: case ReferenceCounting::ObjC: @@ -2311,7 +2303,7 @@ namespace { // Get the reference storage type of the builtin object whose value // witness we can borrow. - if (type->getOwnership() == ReferenceOwnership::Weak) + if (referent->getOptionalObjectType()) valueWitnessReferent = OptionalType::get(valueWitnessReferent) ->getCanonicalType(); diff --git a/lib/IRGen/ReferenceTypeInfo.h b/lib/IRGen/ReferenceTypeInfo.h index bf04267b7e0..cb091a477fe 100644 --- a/lib/IRGen/ReferenceTypeInfo.h +++ b/lib/IRGen/ReferenceTypeInfo.h @@ -23,8 +23,6 @@ namespace swift { namespace irgen { -class WeakTypeInfo; -class UnownedTypeInfo; class TypeConverter; /// \brief An abstract class designed for use when implementing a type @@ -47,58 +45,44 @@ public: virtual void strongRelease(IRGenFunction &IGF, Explosion &in, Atomicity atomicity) const = 0; - /// Strongly retains a value that has come from a safe [unowned] reference. - /// This operation is not supported for all reference types. - virtual void strongRetainUnowned(IRGenFunction &IGF, Explosion &in, - Atomicity atomicity) const = 0; - - /// Strongly retains a value that has come from a safe [unowned] reference. - /// This operation is not supported for all reference types. - virtual void strongRetainUnownedRelease(IRGenFunction &IGF, - Explosion &in, - Atomicity atomicity) const = 0; - - /// Weakly retains a value in the manner of a safe [unowned] reference. - /// This operation is not supported for all reference types. - virtual void unownedRetain(IRGenFunction &IGF, Explosion &in, - Atomicity atomicity) const = 0; - - /// Weakly releases a value in the manner of a safe [unowned] reference. - /// This operation is not supported for all reference types. - virtual void unownedRelease(IRGenFunction &IGF, Explosion &in, +#define REF_STORAGE_HELPER(Name) \ + virtual const TypeInfo *create##Name##StorageType(TypeConverter &TC, \ + bool isOptional) const = 0; +#define NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + virtual void name##TakeStrong(IRGenFunction &IGF, Address addr, \ + Explosion &out, bool isOptional) const = 0; \ + virtual void name##LoadStrong(IRGenFunction &IGF, Address addr, \ + Explosion &out, bool isOptional) const = 0; \ + virtual void name##Init(IRGenFunction &IGF, Explosion &in, \ + Address dest, bool isOptional) const = 0; \ + virtual void name##Assign(IRGenFunction &IGF, Explosion &in, \ + Address dest, bool isOptional) const = 0; +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + virtual void strongRetain##Name(IRGenFunction &IGF, Explosion &in, \ + Atomicity atomicity) const = 0; \ + virtual void strongRetain##Name##Release(IRGenFunction &IGF, \ + Explosion &in, \ + Atomicity atomicity) const = 0; \ + virtual void name##Retain(IRGenFunction &IGF, Explosion &in, \ + Atomicity atomicity) const = 0; \ + virtual void name##Release(IRGenFunction &IGF, Explosion &in, \ Atomicity atomicity) const = 0; - - /// Load a reference from a safe [unowned] reference in memory and - /// destroy the [unowned] location. - virtual void unownedTakeStrong(IRGenFunction &IGF, Address addr, - Explosion &out) const = 0; - - /// Load a reference from a safe [unowned] reference in memory. - virtual void unownedLoadStrong(IRGenFunction &IGF, Address addr, - Explosion &out) const = 0; - - /// Initialize a safe [unowned] reference in memory. - virtual void unownedInit(IRGenFunction &IGF, Explosion &in, - Address dest) const = 0; - - /// Assign to an initialized safe [unowned] reference in memory. - virtual void unownedAssign(IRGenFunction &IGF, Explosion &in, - Address dest) const = 0; - - /// Produce the storage information for [weak] storage. - virtual const WeakTypeInfo *createWeakStorageType(TypeConverter &TC) const = 0; - - /// Produce the storage information for [unowned] storage. - /// - /// The reference-counting operations done by the value operations - /// on the [unowned] storage type are assumed to be basically the - /// same operations as weakRetain and weakRelease. - virtual const TypeInfo *createUnownedStorageType(TypeConverter &TC) - const = 0; - - /// Produce the storage information for @unowned(unsafe) storage. - virtual const TypeInfo *createUnmanagedStorageType(TypeConverter &TC) - const = 0; +#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + REF_STORAGE_HELPER(Name) +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + REF_STORAGE_HELPER(Name) +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, name) \ + REF_STORAGE_HELPER(Name) +#define UNCHECKED_REF_STORAGE(Name, name, ...) \ + REF_STORAGE_HELPER(Name) +#include "swift/AST/ReferenceStorage.def" +#undef REF_STORAGE_HELPER +#undef NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER +#undef ALWAYS_LOADABLE_CHECKED_REF_STORAGE_HELPER static bool classof(const ReferenceTypeInfo *type) { return true; } static bool classof(const TypeInfo *type) { diff --git a/lib/IRGen/SwiftTargetInfo.cpp b/lib/IRGen/SwiftTargetInfo.cpp index c8a5a1c847f..2a272cfa9d0 100644 --- a/lib/IRGen/SwiftTargetInfo.cpp +++ b/lib/IRGen/SwiftTargetInfo.cpp @@ -90,6 +90,9 @@ static void configureX86_64(IRGenModule &IGM, const llvm::Triple &triple, /// Configures target-specific information for 32-bit x86 platforms. static void configureX86(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { + setToMask(target.PointerSpareBits, 32, + SWIFT_ABI_I386_SWIFT_SPARE_BITS_MASK); + // x86 uses objc_msgSend_fpret but not objc_msgSend_fp2ret. target.ObjCUseFPRet = true; setToMask(target.IsObjCPointerBit, 32, SWIFT_ABI_I386_IS_OBJC_BIT); diff --git a/lib/IRGen/WeakTypeInfo.h b/lib/IRGen/WeakTypeInfo.h deleted file mode 100644 index 906f264267d..00000000000 --- a/lib/IRGen/WeakTypeInfo.h +++ /dev/null @@ -1,61 +0,0 @@ -//===--- WeakTypeInfo.h - Supplemental API for [weak] types -----*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -// -// This file defines WeakTypeInfo, which supplements the FixedTypeInfo -// interface for types that implement [weak] references. -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_IRGEN_WEAKTYPEINFO_H -#define SWIFT_IRGEN_WEAKTYPEINFO_H - -#include "FixedTypeInfo.h" - -namespace swift { -namespace irgen { - -/// \brief An abstract class designed for use when implementing a -/// ReferenceStorageType with [weak] ownership. -class WeakTypeInfo : public FixedTypeInfo { -protected: - WeakTypeInfo(llvm::Type *type, Size size, Alignment align, - const SpareBitVector &spareBits) - : FixedTypeInfo(type, size, spareBits, align, IsNotPOD, - IsNotBitwiseTakable, IsFixedSize, - SpecialTypeInfoKind::Weak) {} - - WeakTypeInfo(llvm::Type *type, Size size, Alignment align, - SpareBitVector &&spareBits) - : FixedTypeInfo(type, size, std::move(spareBits), align, IsNotPOD, - IsNotBitwiseTakable, IsFixedSize, - SpecialTypeInfoKind::Weak) {} - -public: - virtual void weakLoadStrong(IRGenFunction &IGF, Address addr, - Explosion &out) const = 0; - virtual void weakTakeStrong(IRGenFunction &IGF, Address addr, - Explosion &out) const = 0; - virtual void weakInit(IRGenFunction &IGF, Explosion &src, - Address dest) const = 0; - virtual void weakAssign(IRGenFunction &IGF, Explosion &src, - Address dest) const = 0; - - static bool classof(const WeakTypeInfo *type) { return true; } - static bool classof(const TypeInfo *type) { - return type->getSpecialTypeInfoKind() == SpecialTypeInfoKind::Weak; - } -}; - -} -} - -#endif diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index adaed21bc3a..92b15c77ec9 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -1792,6 +1792,35 @@ public: "operand's type as its referent type"); \ } #define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + LOADABLE_REF_STORAGE_HELPER(Name, name) \ + void checkStrongRetain##Name##Inst(StrongRetain##Name##Inst *RI) { \ + requireObjectType(Name##StorageType, RI->getOperand(), \ + "Operand of strong_retain_" #name); \ + require(!F.hasQualifiedOwnership(), "strong_retain_" #name " is only in " \ + "functions with unqualified " \ + "ownership"); \ + } \ + void check##Name##RetainInst(Name##RetainInst *RI) { \ + requireObjectType(Name##StorageType, RI->getOperand(), \ + "Operand of " #name "_retain"); \ + require(!F.hasQualifiedOwnership(), \ + #name "_retain is only in functions with unqualified ownership"); \ + } \ + void check##Name##ReleaseInst(Name##ReleaseInst *RI) { \ + requireObjectType(Name##StorageType, RI->getOperand(), \ + "Operand of " #name "_release"); \ + require(!F.hasQualifiedOwnership(), \ + #name "_release is only in functions with unqualified ownership"); \ + } \ + void checkCopy##Name##ValueInst(Copy##Name##ValueInst *I) { \ + requireObjectType(Name##StorageType, I->getOperand(), \ + "Operand of " #name "_retain"); \ + require(F.hasQualifiedOwnership(), \ + "copy_" #name "_value is only valid in functions with qualified " \ + "ownership"); \ + } +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") \ LOADABLE_REF_STORAGE_HELPER(Name, name) \ void checkStrongRetain##Name##Inst(StrongRetain##Name##Inst *RI) { \ auto ty = requireObjectType(Name##StorageType, RI->getOperand(), \ @@ -1826,9 +1855,6 @@ public: /* *NOTE* We allow copy_##name##_value to be used throughout the entire */ \ /* pipeline even though it is a higher level instruction. */ \ } -#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ - NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") \ - ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, name, "...") #define UNCHECKED_REF_STORAGE(Name, name, ...) \ LOADABLE_REF_STORAGE_HELPER(Name, name) #include "swift/AST/ReferenceStorage.def" diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp index 6760baab86a..aafb95ac854 100644 --- a/lib/SILGen/SILGenBuilder.cpp +++ b/lib/SILGen/SILGenBuilder.cpp @@ -290,7 +290,7 @@ ManagedValue SILGenBuilder::createCopyValue(SILLocation loc, return SGF.emitManagedRValueWithCleanup(result, lowering); } -#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ ManagedValue \ SILGenBuilder::createCopy##Name##Value(SILLocation loc, \ ManagedValue originalValue) { \ @@ -300,6 +300,13 @@ ManagedValue SILGenBuilder::createCopyValue(SILLocation loc, SILValue result = createCopy##Name##Value(loc, originalValue.getValue()); \ return SGF.emitManagedRValueWithCleanup(result); \ } +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + ManagedValue \ + SILGenBuilder::createCopy##Name##Value(SILLocation loc, \ + ManagedValue originalValue) { \ + SILValue result = createCopy##Name##Value(loc, originalValue.getValue()); \ + return SGF.emitManagedRValueWithCleanup(result); \ + } #define UNCHECKED_REF_STORAGE(Name, ...) \ ManagedValue \ SILGenBuilder::createUnsafeCopy##Name##Value(SILLocation loc, \ diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index dea37fafa6e..7534b320ab9 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -3005,13 +3005,15 @@ SILValue SILGenFunction::emitConversionToSemanticRValue(SILLocation loc, case ReferenceOwnership::Name: \ /* Address-only storage types are handled with their underlying type. */ \ llvm_unreachable("address-only pointers are handled elsewhere"); -#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case ReferenceOwnership::Name: \ + return B.createCopy##Name##Value(loc, src); +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case ReferenceOwnership::Name: { \ /* For loadable reference storage types, we need to generate a strong */ \ /* retain and strip the box. */ \ - auto type = storageType.castTo(); \ - assert(type->isLoadable(ResilienceExpansion::Maximal)); \ - (void)type; \ + assert(storageType.castTo()->isLoadable( \ + ResilienceExpansion::Maximal)); \ return B.createCopy##Name##Value(loc, src); \ } #define UNCHECKED_REF_STORAGE(Name, ...) \ @@ -3260,7 +3262,14 @@ SILValue SILGenFunction::emitConversionFromSemanticValue(SILLocation loc, #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case ReferenceOwnership::Name: \ llvm_unreachable("address-only types are never loadable"); -#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ +#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case ReferenceOwnership::Name: { \ + SILValue value = B.createRefTo##Name(loc, semanticValue, storageType); \ + value = B.createCopyValue(loc, value); \ + B.emitDestroyValueOperation(loc, semanticValue); \ + return value; \ + } +#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case ReferenceOwnership::Name: { \ /* For loadable types, place into a box. */ \ auto type = storageType.castTo(); \ diff --git a/test/IRGen/enum_objc.sil b/test/IRGen/enum_objc.sil index dd3f1085c62..78adb0e2693 100644 --- a/test/IRGen/enum_objc.sil +++ b/test/IRGen/enum_objc.sil @@ -98,3 +98,31 @@ w_dest: end: return undef : $() } + +protocol delegateProtocol : AnyObject { } + +struct StructWithWeakVar { +weak var delegate: delegateProtocol? +} + +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @weak_optional(%T9enum_objc17StructWithWeakVarVSg* noalias nocapture dereferenceable({{.*}})) +sil @weak_optional : $@convention(thin) (@in StructWithWeakVar?) -> () { +entry(%x : $*StructWithWeakVar?): + // CHECK: icmp eq [[WORD:i32|i64]] {{%.*}}, 0 + switch_enum_addr %x : $*StructWithWeakVar?, + case #Optional.some!enumelt.1: a, + case #Optional.none!enumelt: b +a: + br x +b: + // CHECK: store [[WORD]] 0 + // CHECK: store [[WORD]] 1 + inject_enum_addr %x : $*StructWithWeakVar?, #Optional.none!enumelt + br x + +x: + return undef : $() +} + +// Weak existentials allow extra inhabitants if not @objc, therefore StructWithWeakVar must emit: +// CHECK: define linkonce_odr hidden void @"$S9enum_objc17StructWithWeakVarVwxs" diff --git a/test/IRGen/reference_storage_extra_inhabitants.sil b/test/IRGen/reference_storage_extra_inhabitants.sil index 2de42c4e547..9e4fc57d8bf 100644 --- a/test/IRGen/reference_storage_extra_inhabitants.sil +++ b/test/IRGen/reference_storage_extra_inhabitants.sil @@ -1,5 +1,4 @@ -// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -disable-objc-interop -emit-ir -primary-file %s | %FileCheck %s -// XFAIL: * +// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -disable-objc-interop -emit-ir -primary-file %s | %FileCheck %s -DWORD=i%target-ptrsize sil_stage canonical @@ -15,9 +14,9 @@ struct S { func example(_ os: S?) -// CHECK-LABEL: define hidden swiftcc void @"$S35reference_storage_extra_inhabitants7exampleyyAA1SVSgF"(i64) #0 +// CHECK-LABEL: define hidden swiftcc void @"$S35reference_storage_extra_inhabitants7exampleyyAA1SVSgF" // CHECK-NEXT: entry: -// CHECK-NEXT: %1 = icmp eq i64 %0, 1 +// CHECK-NEXT: %1 = icmp eq [[WORD]] %0, 1 sil hidden @$S35reference_storage_extra_inhabitants7exampleyyAA1SVSgF : $@convention(thin) (Optional) -> () { bb0(%0 : $Optional): switch_enum %0 : $Optional, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb1 // id: %2 diff --git a/test/IRGen/type_layout_reference_storage.swift b/test/IRGen/type_layout_reference_storage.swift index 9b545e54327..2305cdfe0da 100644 --- a/test/IRGen/type_layout_reference_storage.swift +++ b/test/IRGen/type_layout_reference_storage.swift @@ -1,4 +1,5 @@ -// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK -DINT=i%target-ptrsize +// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s -enable-objc-interop | %FileCheck %s -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-objc-%target-ptrsize +// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s -disable-objc-interop | %FileCheck %s -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-native-%target-ptrsize class C {} protocol P: class {} @@ -29,46 +30,54 @@ struct ReferenceStorageTypeLayout { // CHECK: store i8** getelementptr inbounds (i8*, i8** @"$SBoSgXwWV", i32 8) weak var nwi: Native! - // -- Open-code layout for protocol types with witness tables. - // Note that the layouts for unowned(safe) references are - // only bitwise takable when ObjC interop is disabled. - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[UNOWNED_XI:[0-9a-f]+]]{{(,|_bt,)}} i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[UNOWNED_XI:[0-9a-f]+]]{{(,|_bt,)}} i32 0, i32 0) - unowned(safe) var ps: P - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI:[0-9a-f]+]]_pod, i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI:[0-9a-f]+]]_pod, i32 0, i32 0) + // -- Open-code layout for protocol types with witness tables. Note: + // 1) The layouts for unowned(safe) references are only bitwise takable + // when ObjC interop is disabled. + // 2) 0x7fffffff is the max extra inhabitant count, but not all types in + // all scenarios. + // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod, i32 0, i32 0) + // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI:[0-9a-f][0-9a-f][0-9a-f]+]]_pod, i32 0, i32 0) unowned(unsafe) var pu: P - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[WEAK_XI:[0-9a-f]+]], i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_4_[[WEAK_XI:[0-9a-f]+]], i32 0, i32 0) + // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[REF_XI]]_bt, i32 0, i32 0) + // CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff, i32 0, i32 0) + // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_[[REF_XI]]_bt, i32 0, i32 0) + // CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_7fffffff, i32 0, i32 0) + unowned(safe) var ps: P + // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff, i32 0, i32 0) + // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_7fffffff, i32 0, i32 0) weak var pwo: P? - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_[[WEAK_XI]], i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_8_4_[[WEAK_XI]], i32 0, i32 0) + // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_16_8_7fffffff, i32 0, i32 0) + // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_8_4_7fffffff, i32 0, i32 0) weak var pwi: P! - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[UNOWNED_XI]]{{(,|_bt,)}} i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[UNOWNED_XI]]{{(,|_bt,)}} i32 0, i32 0) + // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_bt, i32 0, i32 0) + // CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0) + // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_bt, i32 0, i32 0) + // CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0) unowned(safe) var pqs: P & Q // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_pod, i32 0, i32 0) // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_pod, i32 0, i32 0) unowned(unsafe) var pqu: P & Q - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[WEAK_XI]], i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_12_4_[[WEAK_XI]], i32 0, i32 0) + // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0) + // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0) weak var pqwo: (P & Q)? - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[WEAK_XI]], i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_12_4_[[WEAK_XI]], i32 0, i32 0) + // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0) + // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0) weak var pqwi: (P & Q)! - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[UNOWNED_XI]]{{(,|_bt,)}} i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[UNOWNED_XI]]{{(,|_bt,)}} i32 0, i32 0) + // CHECK-native-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_bt, i32 0, i32 0) + // CHECK-objc-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff_bt, i32 0, i32 0) + // CHECK-native-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_bt, i32 0, i32 0) + // CHECK-objc-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff_bt, i32 0, i32 0) unowned(safe) var pqcs: P & Q & C // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[REF_XI]]_pod, i32 0, i32 0) // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_[[REF_XI]]_pod, i32 0, i32 0) unowned(unsafe) var pqcu: P & Q & C - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[WEAK_XI]], i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_12_4_[[WEAK_XI]], i32 0, i32 0) + // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0) + // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0) weak var pqcwo: (P & Q & C)? - // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_[[WEAK_XI]], i32 0, i32 0) - // CHECK-32: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @type_layout_12_4_[[WEAK_XI]], i32 0, i32 0) + // CHECK-64: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_24_8_7fffffff, i32 0, i32 0) + // CHECK-32: store i8** getelementptr inbounds ([4 x i8*], [4 x i8*]* @type_layout_12_4_7fffffff, i32 0, i32 0) weak var pqcwi: (P & Q & C)! // -- Unknown-refcounted existential without witness tables.