Properly flag opaque existential types as not being

bitwise-takable.

Swift SVN r20803
This commit is contained in:
John McCall
2014-07-31 02:03:56 +00:00
parent 36a27a61a4
commit c367362f22
5 changed files with 106 additions and 6 deletions

View File

@@ -495,11 +495,7 @@ namespace {
OpaqueExistentialTypeInfo(llvm::Type *ty, Size size, Alignment align, OpaqueExistentialTypeInfo(llvm::Type *ty, Size size, Alignment align,
ArrayRef<ProtocolEntry> protocols) ArrayRef<ProtocolEntry> protocols)
: IndirectTypeInfo(ty, size, llvm::BitVector{}, align, : IndirectTypeInfo(ty, size, llvm::BitVector{}, align,
IsNotPOD, IsNotPOD, IsNotBitwiseTakable),
// We ensure opaque existentials are always bitwise-
// takable by storing non-bitwise-takable objects out
// of line.
IsBitwiseTakable),
NumProtocols(protocols.size()) { NumProtocols(protocols.size()) {
for (unsigned i = 0; i != NumProtocols; ++i) { for (unsigned i = 0; i != NumProtocols; ++i) {

View File

@@ -184,6 +184,7 @@ struct LLVM_LIBRARY_VISIBILITY OpaqueExistentialBox
static constexpr size_t alignment = alignof(Container); static constexpr size_t alignment = alignof(Container);
static constexpr size_t stride = sizeof(Container); static constexpr size_t stride = sizeof(Container);
static constexpr size_t isPOD = false; static constexpr size_t isPOD = false;
static constexpr bool isBitwiseTakable = false;
static constexpr unsigned numExtraInhabitants = 0; static constexpr unsigned numExtraInhabitants = 0;
}; };
@@ -321,6 +322,7 @@ struct LLVM_LIBRARY_VISIBILITY ClassExistentialBox
static constexpr size_t alignment = alignof(Container); static constexpr size_t alignment = alignof(Container);
static constexpr size_t stride = sizeof(Container); static constexpr size_t stride = sizeof(Container);
static constexpr size_t isPOD = false; static constexpr size_t isPOD = false;
static constexpr size_t isBitwiseTakable = true;
}; };
/// A non-fixed box implementation class for an class existential /// A non-fixed box implementation class for an class existential

View File

@@ -26,7 +26,6 @@
#include <cctype> #include <cctype>
#include <dispatch/dispatch.h> #include <dispatch/dispatch.h>
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Hashing.h" #include "llvm/ADT/Hashing.h"
#include "ExistentialMetadataImpl.h" #include "ExistentialMetadataImpl.h"
#include "Debug.h" #include "Debug.h"
@@ -1497,6 +1496,7 @@ getOpaqueExistentialValueWitnesses(unsigned numWitnessTables) {
vwt->flags = ValueWitnessFlags() vwt->flags = ValueWitnessFlags()
.withAlignment(Box::Container::getAlignment(numWitnessTables)) .withAlignment(Box::Container::getAlignment(numWitnessTables))
.withPOD(false) .withPOD(false)
.withBitwiseTakable(false)
.withInlineStorage(false) .withInlineStorage(false)
.withExtraInhabitants(false); .withExtraInhabitants(false);
vwt->stride = Box::Container::getStride(numWitnessTables); vwt->stride = Box::Container::getStride(numWitnessTables);
@@ -1547,6 +1547,7 @@ getClassExistentialValueWitnesses(unsigned numWitnessTables) {
vwt->flags = ValueWitnessFlags() vwt->flags = ValueWitnessFlags()
.withAlignment(Box::Container::getAlignment(numWitnessTables)) .withAlignment(Box::Container::getAlignment(numWitnessTables))
.withPOD(false) .withPOD(false)
.withBitwiseTakable(true)
.withInlineStorage(false) .withInlineStorage(false)
.withExtraInhabitants(true); .withExtraInhabitants(true);
vwt->stride = Box::Container::getStride(numWitnessTables); vwt->stride = Box::Container::getStride(numWitnessTables);

View File

@@ -103,6 +103,7 @@ struct NativeBox {
static constexpr size_t alignment = Alignment; static constexpr size_t alignment = Alignment;
static constexpr size_t stride = Stride; static constexpr size_t stride = Stride;
static constexpr size_t isPOD = std::is_pod<T>::value; static constexpr size_t isPOD = std::is_pod<T>::value;
static constexpr bool isBitwiseTakable = isPOD;
static constexpr unsigned numExtraInhabitants = 0; static constexpr unsigned numExtraInhabitants = 0;
static void destroy(T *value) { static void destroy(T *value) {
@@ -197,6 +198,7 @@ template <class Impl, class T> struct RetainableBoxBase {
static constexpr size_t alignment = alignof(T); static constexpr size_t alignment = alignof(T);
static constexpr size_t stride = sizeof(T); static constexpr size_t stride = sizeof(T);
static constexpr bool isPOD = false; static constexpr bool isPOD = false;
static constexpr bool isBitwiseTakable = true;
static void destroy(T *addr) { static void destroy(T *addr) {
Impl::release(*addr); Impl::release(*addr);
@@ -339,6 +341,7 @@ public:
static constexpr size_t endOffset = StartOffset; static constexpr size_t endOffset = StartOffset;
static constexpr size_t alignment = 1; static constexpr size_t alignment = 1;
static constexpr bool isPOD = true; static constexpr bool isPOD = true;
static constexpr bool isBitwiseTakable = true;
public: public:
#define COPY_OP(OP) \ #define COPY_OP(OP) \
@@ -370,6 +373,8 @@ public:
(NextHelper::alignment > EltBox::alignment (NextHelper::alignment > EltBox::alignment
? NextHelper::alignment : EltBox::alignment); ? NextHelper::alignment : EltBox::alignment);
static constexpr bool isPOD = EltBox::isPOD && NextHelper::isPOD; static constexpr bool isPOD = EltBox::isPOD && NextHelper::isPOD;
static constexpr bool isBitwiseTakable =
EltBox::isBitwiseTakable && NextHelper::isBitwiseTakable;
private: private:
static constexpr size_t eltToNextOffset = (nextOffset - eltOffset); static constexpr size_t eltToNextOffset = (nextOffset - eltOffset);
@@ -412,6 +417,7 @@ struct AggregateBox {
static constexpr size_t alignment = Helper::alignment; static constexpr size_t alignment = Helper::alignment;
static constexpr size_t stride = roundUpToAlignment(size, alignment); static constexpr size_t stride = roundUpToAlignment(size, alignment);
static constexpr bool isPOD = Helper::isPOD; static constexpr bool isPOD = Helper::isPOD;
static constexpr bool isBitwiseTakable = Helper::isBitwiseTakable;
/// Don't collect extra inhabitants from the members by default. /// Don't collect extra inhabitants from the members by default.
static constexpr unsigned numExtraInhabitants = 0; static constexpr unsigned numExtraInhabitants = 0;
@@ -659,12 +665,14 @@ struct ValueWitnesses : BufferValueWitnesses<ValueWitnesses<Box>,
static constexpr size_t stride = Box::stride; static constexpr size_t stride = Box::stride;
static constexpr size_t alignment = Box::alignment; static constexpr size_t alignment = Box::alignment;
static constexpr bool isPOD = Box::isPOD; static constexpr bool isPOD = Box::isPOD;
static constexpr bool isBitwiseTakable = Box::isBitwiseTakable;
static constexpr unsigned numExtraInhabitants = Box::numExtraInhabitants; static constexpr unsigned numExtraInhabitants = Box::numExtraInhabitants;
static constexpr bool hasExtraInhabitants = (numExtraInhabitants != 0); static constexpr bool hasExtraInhabitants = (numExtraInhabitants != 0);
static constexpr ValueWitnessFlags flags = static constexpr ValueWitnessFlags flags =
ValueWitnessFlags().withAlignmentMask(alignment - 1) ValueWitnessFlags().withAlignmentMask(alignment - 1)
.withInlineStorage(Base::isInline) .withInlineStorage(Base::isInline)
.withPOD(isPOD) .withPOD(isPOD)
.withBitwiseTakable(isBitwiseTakable)
.withExtraInhabitants(hasExtraInhabitants); .withExtraInhabitants(hasExtraInhabitants);
static constexpr ExtraInhabitantFlags extraInhabitantFlags = static constexpr ExtraInhabitantFlags extraInhabitantFlags =
ExtraInhabitantFlags().withNumExtraInhabitants(numExtraInhabitants); ExtraInhabitantFlags().withNumExtraInhabitants(numExtraInhabitants);

View File

@@ -328,3 +328,96 @@ TEST(MetadataTest, getGenericMetadata_SuperclassWithUnexpectedPrefix) {
ASSERT_EQ(4 * sizeof(void*) + sizeof(HeapMetadataHeader), ASSERT_EQ(4 * sizeof(void*) + sizeof(HeapMetadataHeader),
inst->getClassAddressPoint()); inst->getClassAddressPoint());
} }
static ProtocolDescriptor OpaqueProto1 = { "OpaqueProto1", nullptr,
ProtocolDescriptorFlags().withSwift(true).withNeedsWitnessTable(true)
.withClassConstraint(ProtocolClassConstraint::Any)
};
static ProtocolDescriptor OpaqueProto2 = { "OpaqueProto2", nullptr,
ProtocolDescriptorFlags().withSwift(true).withNeedsWitnessTable(true)
.withClassConstraint(ProtocolClassConstraint::Any)
};
static ProtocolDescriptor OpaqueProto3 = { "OpaqueProto3", nullptr,
ProtocolDescriptorFlags().withSwift(true).withNeedsWitnessTable(true)
.withClassConstraint(ProtocolClassConstraint::Any)
};
static ProtocolDescriptor ClassProto1 = { "ClassProto1", nullptr,
ProtocolDescriptorFlags().withSwift(true).withNeedsWitnessTable(true)
.withClassConstraint(ProtocolClassConstraint::Class)
};
TEST(MetadataTest, getExistentialTypeMetadata_opaque) {
const ProtocolDescriptor *protoList1[] = {
&OpaqueProto1
};
auto ex1a = swift_getExistentialTypeMetadata(1, protoList1);
auto ex1b = swift_getExistentialTypeMetadata(1, protoList1);
ASSERT_EQ(ex1a, ex1b);
ASSERT_EQ(MetadataKind::Existential, ex1a->getKind());
ASSERT_EQ(5 * sizeof(void*), ex1a->getValueWitnesses()->getSize());
ASSERT_EQ(alignof(void*), ex1a->getValueWitnesses()->getAlignment());
ASSERT_FALSE(ex1a->getValueWitnesses()->isPOD());
ASSERT_FALSE(ex1a->getValueWitnesses()->isBitwiseTakable());
const ProtocolDescriptor *protoList2[] = {
&OpaqueProto1, &OpaqueProto2
};
auto ex2a = swift_getExistentialTypeMetadata(2, protoList2);
auto ex2b = swift_getExistentialTypeMetadata(2, protoList2);
ASSERT_EQ(ex2a, ex2b);
ASSERT_EQ(MetadataKind::Existential, ex2a->getKind());
ASSERT_EQ(6 * sizeof(void*), ex2a->getValueWitnesses()->getSize());
ASSERT_EQ(alignof(void*), ex2a->getValueWitnesses()->getAlignment());
ASSERT_FALSE(ex2a->getValueWitnesses()->isPOD());
ASSERT_FALSE(ex2a->getValueWitnesses()->isBitwiseTakable());
const ProtocolDescriptor *protoList3[] = {
&OpaqueProto1, &OpaqueProto2, &OpaqueProto3
};
auto ex3a = swift_getExistentialTypeMetadata(3, protoList3);
auto ex3b = swift_getExistentialTypeMetadata(3, protoList3);
ASSERT_EQ(ex3a, ex3b);
ASSERT_EQ(MetadataKind::Existential, ex3a->getKind());
ASSERT_EQ(7 * sizeof(void*), ex3a->getValueWitnesses()->getSize());
ASSERT_EQ(alignof(void*), ex3a->getValueWitnesses()->getAlignment());
ASSERT_FALSE(ex3a->getValueWitnesses()->isPOD());
ASSERT_FALSE(ex3a->getValueWitnesses()->isBitwiseTakable());
}
TEST(MetadataTest, getExistentialTypeMetadata_class) {
const ProtocolDescriptor *protoList1[] = {
&ClassProto1
};
auto ex1a = swift_getExistentialTypeMetadata(1, protoList1);
auto ex1b = swift_getExistentialTypeMetadata(1, protoList1);
ASSERT_EQ(ex1a, ex1b);
ASSERT_EQ(MetadataKind::Existential, ex1a->getKind());
ASSERT_EQ(2 * sizeof(void*), ex1a->getValueWitnesses()->getSize());
ASSERT_EQ(alignof(void*), ex1a->getValueWitnesses()->getAlignment());
ASSERT_FALSE(ex1a->getValueWitnesses()->isPOD());
ASSERT_TRUE(ex1a->getValueWitnesses()->isBitwiseTakable());
const ProtocolDescriptor *protoList2[] = {
&OpaqueProto1, &ClassProto1
};
auto ex2a = swift_getExistentialTypeMetadata(2, protoList2);
auto ex2b = swift_getExistentialTypeMetadata(2, protoList2);
ASSERT_EQ(ex2a, ex2b);
ASSERT_EQ(MetadataKind::Existential, ex2a->getKind());
ASSERT_EQ(3 * sizeof(void*), ex2a->getValueWitnesses()->getSize());
ASSERT_EQ(alignof(void*), ex2a->getValueWitnesses()->getAlignment());
ASSERT_FALSE(ex2a->getValueWitnesses()->isPOD());
ASSERT_TRUE(ex2a->getValueWitnesses()->isBitwiseTakable());
const ProtocolDescriptor *protoList3[] = {
&OpaqueProto1, &OpaqueProto2, &ClassProto1
};
auto ex3a = swift_getExistentialTypeMetadata(3, protoList3);
auto ex3b = swift_getExistentialTypeMetadata(3, protoList3);
ASSERT_EQ(ex3a, ex3b);
ASSERT_EQ(MetadataKind::Existential, ex3a->getKind());
ASSERT_EQ(4 * sizeof(void*), ex3a->getValueWitnesses()->getSize());
ASSERT_EQ(alignof(void*), ex3a->getValueWitnesses()->getAlignment());
ASSERT_FALSE(ex3a->getValueWitnesses()->isPOD());
ASSERT_TRUE(ex3a->getValueWitnesses()->isBitwiseTakable());
}