Files
swift-mirror/unittests/runtime/Metadata.cpp
2013-11-01 20:21:46 +00:00

248 lines
8.4 KiB
C++

//===- swift/unittests/runtime/Metadata.cpp - Metadata tests --------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Runtime/Metadata.h"
#include "gtest/gtest.h"
#include <vector>
using namespace swift;
/// Some unique global pointers.
char Global1 = 0;
char Global2 = 0;
char Global3 = 0;
/// The general structure of a generic metadata.
template <unsigned NumFields>
struct GenericMetadataTest {
GenericMetadata Header;
void *Fields[NumFields];
};
GenericMetadataTest<3> MetadataTest1 = {
// Header
{
// fill function
[](void *metadata, const void *args) {
auto metadataWords = reinterpret_cast<const void**>(metadata);
auto argsWords = reinterpret_cast<const void* const*>(args);
metadataWords[0] = argsWords[0];
metadataWords[2] = argsWords[0];
},
3 * sizeof(void*), // metadata size
1, // num arguments
0, // address point
{} // private data
},
// Fields
{
nullptr,
&Global1,
nullptr
}
};
TEST(MetadataTest, getGenericMetadata) {
auto metadataTemplate = (GenericMetadata*) &MetadataTest1;
void *args[] = { &Global2 };
auto inst1a = swift_getGenericMetadata(metadataTemplate, args);
auto inst1b = swift_getGenericMetadata(metadataTemplate, args);
ASSERT_EQ(inst1a, inst1b);
void * const *fields = reinterpret_cast<void * const *>(inst1a);
ASSERT_EQ(&Global2, fields[0]);
ASSERT_EQ(&Global1, fields[1]);
ASSERT_EQ(&Global2, fields[2]);
args[0] = &Global3;
auto inst2a = swift_getGenericMetadata(metadataTemplate, args);
auto inst2b = swift_getGenericMetadata(metadataTemplate, args);
ASSERT_EQ(inst2a, inst2b);
ASSERT_NE(inst1a, inst2a);
fields = reinterpret_cast<void * const *>(inst2a);
ASSERT_EQ(&Global3, fields[0]);
ASSERT_EQ(&Global1, fields[1]);
ASSERT_EQ(&Global3, fields[2]);
}
FullMetadata<ClassMetadata> MetadataTest2 = {
{ { nullptr }, { &_TWVBo } },
{ { { MetadataKind::Class } }, nullptr, 0, nullptr, 0, 0 }
};
TEST(MetadataTest, getMetatypeMetadata) {
auto inst1a = swift_getMetatypeMetadata(&_TMdBi64_.base);
auto inst1b = swift_getMetatypeMetadata(&_TMdBi64_.base);
ASSERT_EQ(inst1a, inst1b);
auto inst2a = swift_getMetatypeMetadata(&_TMdBi32_.base);
auto inst2b = swift_getMetatypeMetadata(&_TMdBi32_.base);
ASSERT_EQ(inst2a, inst2b);
// Both of these are trivial metatypes.
ASSERT_EQ(size_t(0), inst1a->getValueWitnesses()->size);
ASSERT_EQ(size_t(0), inst2a->getValueWitnesses()->size);
auto inst3a = swift_getMetatypeMetadata(&MetadataTest2);
auto inst3b = swift_getMetatypeMetadata(&MetadataTest2);
ASSERT_EQ(inst3a, inst3b);
// The representation here should be non-trivial.
ASSERT_EQ(sizeof(void*), inst3a->getValueWitnesses()->size);
// Going out another level of abstraction on the class metatype
// should leave us with another non-trivial metatype.
auto inst4a = swift_getMetatypeMetadata(inst3a);
auto inst4b = swift_getMetatypeMetadata(inst3a);
ASSERT_EQ(inst4a, inst4b);
ASSERT_EQ(sizeof(void*), inst4a->getValueWitnesses()->size);
// Similarly, going out a level of abstraction on a trivial
// metatype should give us a trivial metatype.
auto inst5a = swift_getMetatypeMetadata(inst1a);
auto inst5b = swift_getMetatypeMetadata(inst1a);
ASSERT_EQ(inst5a, inst5b);
ASSERT_EQ(size_t(0), inst5a->getValueWitnesses()->size);
// After all this, the instance type fields should still be valid.
ASSERT_EQ(&_TMdBi64_.base, inst1a->InstanceType);
ASSERT_EQ(&_TMdBi32_.base, inst2a->InstanceType);
ASSERT_EQ(&MetadataTest2, inst3a->InstanceType);
ASSERT_EQ(inst3a, inst4a->InstanceType);
ASSERT_EQ(inst1a, inst5a->InstanceType);
}
ProtocolDescriptor ProtocolA{
"_TMp8Metadata9ProtocolA",
nullptr,
ProtocolDescriptorFlags()
.withSwift(true)
.withClassConstraint(ProtocolClassConstraint::Any)
.withNeedsWitnessTable(true)
};
ProtocolDescriptor ProtocolB{
"_TMp8Metadata9ProtocolB",
nullptr,
ProtocolDescriptorFlags()
.withSwift(true)
.withClassConstraint(ProtocolClassConstraint::Any)
.withNeedsWitnessTable(true)
};
ProtocolDescriptor ProtocolClassConstrained{
"_TMp8Metadata24ProtocolClassConstrained",
nullptr,
ProtocolDescriptorFlags()
.withSwift(true)
.withClassConstraint(ProtocolClassConstraint::Class)
.withNeedsWitnessTable(true)
};
ProtocolDescriptor ProtocolNoWitnessTable{
"_TMp8Metadata22ProtocolNoWitnessTable",
nullptr,
ProtocolDescriptorFlags()
.withSwift(true)
.withClassConstraint(ProtocolClassConstraint::Class)
.withNeedsWitnessTable(false)
};
static const ExistentialTypeMetadata *test_getExistentialMetadata(
std::initializer_list<const ProtocolDescriptor *> descriptors)
{
std::vector<const ProtocolDescriptor *> mutDescriptors(descriptors);
return swift_getExistentialTypeMetadata(mutDescriptors.size(),
mutDescriptors.data());
}
TEST(MetadataTest, getExistentialMetadata) {
{
auto any1 = test_getExistentialMetadata({});
auto any2 = test_getExistentialMetadata({});
ASSERT_EQ(any1, any2);
ASSERT_EQ(MetadataKind::Existential, any1->getKind());
ASSERT_EQ(0U, any1->Flags.getNumWitnessTables());
ASSERT_EQ(ProtocolClassConstraint::Any, any1->Flags.getClassConstraint());
ASSERT_EQ(0U, any1->Protocols.NumProtocols);
}
{
auto a1 = test_getExistentialMetadata({&ProtocolA});
auto a2 = test_getExistentialMetadata({&ProtocolA});
ASSERT_EQ(a1, a2);
ASSERT_EQ(MetadataKind::Existential, a1->getKind());
ASSERT_EQ(1U, a1->Flags.getNumWitnessTables());
ASSERT_EQ(ProtocolClassConstraint::Any, a1->Flags.getClassConstraint());
ASSERT_EQ(1U, a1->Protocols.NumProtocols);
ASSERT_EQ(&ProtocolA, a1->Protocols[0]);
auto b = test_getExistentialMetadata({&ProtocolB});
ASSERT_NE(a1, b);
ASSERT_EQ(MetadataKind::Existential, b->getKind());
ASSERT_EQ(1U, b->Flags.getNumWitnessTables());
ASSERT_EQ(ProtocolClassConstraint::Any, b->Flags.getClassConstraint());
ASSERT_EQ(1U, b->Protocols.NumProtocols);
ASSERT_EQ(&ProtocolB, b->Protocols[0]);
}
// protocol compositions are order-invariant
{
auto ab = test_getExistentialMetadata({&ProtocolA, &ProtocolB});
auto ba = test_getExistentialMetadata({&ProtocolB, &ProtocolA});
ASSERT_EQ(ab, ba);
ASSERT_EQ(MetadataKind::Existential, ab->getKind());
ASSERT_EQ(2U, ab->Flags.getNumWitnessTables());
ASSERT_EQ(ProtocolClassConstraint::Any, ab->Flags.getClassConstraint());
ASSERT_EQ(2U, ab->Protocols.NumProtocols);
ASSERT_TRUE((ab->Protocols[0]==&ProtocolA && ab->Protocols[1]==&ProtocolB)
|| (ab->Protocols[0]==&ProtocolB && ab->Protocols[1]==&ProtocolA));
}
{
auto classConstrained
= test_getExistentialMetadata({&ProtocolClassConstrained});
ASSERT_EQ(MetadataKind::Existential, classConstrained->getKind());
ASSERT_EQ(1U, classConstrained->Flags.getNumWitnessTables());
ASSERT_EQ(ProtocolClassConstraint::Class,
classConstrained->Flags.getClassConstraint());
ASSERT_EQ(1U, classConstrained->Protocols.NumProtocols);
ASSERT_EQ(&ProtocolClassConstrained, classConstrained->Protocols[0]);
}
{
auto noWitnessTable
= test_getExistentialMetadata({&ProtocolNoWitnessTable});
ASSERT_EQ(MetadataKind::Existential, noWitnessTable->getKind());
ASSERT_EQ(0U, noWitnessTable->Flags.getNumWitnessTables());
ASSERT_EQ(ProtocolClassConstraint::Class,
noWitnessTable->Flags.getClassConstraint());
ASSERT_EQ(1U, noWitnessTable->Protocols.NumProtocols);
ASSERT_EQ(&ProtocolNoWitnessTable, noWitnessTable->Protocols[0]);
}
{
auto mixedWitnessTable
= test_getExistentialMetadata({&ProtocolNoWitnessTable,
&ProtocolA, &ProtocolB});
ASSERT_EQ(MetadataKind::Existential, mixedWitnessTable->getKind());
ASSERT_EQ(2U, mixedWitnessTable->Flags.getNumWitnessTables());
ASSERT_EQ(ProtocolClassConstraint::Class,
mixedWitnessTable->Flags.getClassConstraint());
ASSERT_EQ(3U, mixedWitnessTable->Protocols.NumProtocols);
}
}