IRGen/Runtime: Use only the 'layout' subset of the vwtable to perform value type layout.

Full type metadata isn't necessary to calculate the runtime layout of a dependent struct or enum; we only need the non-function data from the value witness table (size, alignment, extra inhabitant count, and POD/BT/etc. flags). This can be generated more efficiently than the type metadata for many types--if we know a specific instantiation is fixed-layout, we can regenerate the layout information, or if we know the type has the same layout as another well-known type, we can get the layout from a common value witness table. This breaks a deadlock in most (but not all) cases where a value type is recursive using classes or fixed-layout indirected structs like UnsafePointer. rdar://problem/19898165

This time, factor out the ObjC-dependent parts of the tests so they only run with ObjC interop.

Swift SVN r30266
This commit is contained in:
Joe Groff
2015-07-16 15:38:17 +00:00
parent a41d7b7292
commit ec61fa4c5a
21 changed files with 736 additions and 88 deletions

View File

@@ -925,9 +925,9 @@ static size_t roundUpToAlignMask(size_t size, size_t alignMask) {
/// final layout characteristics of the type.
/// FUNCTOR should have signature:
/// void (size_t index, const Metadata *type, size_t offset)
template<typename FUNCTOR>
template<typename FUNCTOR, typename LAYOUT>
void performBasicLayout(BasicLayout &layout,
const Metadata * const *elements,
const LAYOUT * const *elements,
size_t numElements,
FUNCTOR &&f) {
size_t size = layout.size;
@@ -938,17 +938,17 @@ void performBasicLayout(BasicLayout &layout,
auto elt = elements[i];
// Lay out this element.
auto eltVWT = elt->getValueWitnesses();
size = roundUpToAlignMask(size, eltVWT->getAlignmentMask());
const TypeLayout *eltLayout = elt->getTypeLayout();
size = roundUpToAlignMask(size, eltLayout->flags.getAlignmentMask());
// Report this record to the functor.
f(i, elt, size);
// Update the size and alignment of the aggregate..
size += eltVWT->size;
alignMask = std::max(alignMask, eltVWT->getAlignmentMask());
if (!eltVWT->isPOD()) isPOD = false;
if (!eltVWT->isBitwiseTakable()) isBitwiseTakable = false;
size += eltLayout->size;
alignMask = std::max(alignMask, eltLayout->flags.getAlignmentMask());
if (!eltLayout->flags.isPOD()) isPOD = false;
if (!eltLayout->flags.isBitwiseTakable()) isBitwiseTakable = false;
}
bool isInline = ValueWitnessTable::isValueInline(size, alignMask + 1);
@@ -1250,8 +1250,8 @@ static OpaqueValue *pod_direct_initializeArrayWithTakeFrontToBack(
#define pod_indirect_initializeArrayWithTakeBackToFront \
pod_direct_initializeArrayWithTakeFrontToBack
static constexpr uintptr_t sizeWithAlignmentMask(uintptr_t size,
uintptr_t alignmentMask) {
static constexpr uint64_t sizeWithAlignmentMask(uint64_t size,
uint64_t alignmentMask) {
return (size << 16) | alignmentMask;
}
@@ -1292,6 +1292,9 @@ void swift::installCommonValueWitnesses(ValueWitnessTable *vwtable) {
case sizeWithAlignmentMask(16, 15):
commonVWT = &_TWVBi128_;
break;
case sizeWithAlignmentMask(32, 31):
commonVWT = &_TWVBi256_;
break;
}
#define INSTALL_POD_COMMON_WITNESS(NAME) vwtable->NAME = commonVWT->NAME;
@@ -1337,12 +1340,12 @@ void swift::installCommonValueWitnesses(ValueWitnessTable *vwtable) {
/// Initialize the value witness table and struct field offset vector for a
/// struct, using the "Universal" layout strategy.
void swift::swift_initStructMetadata_UniversalStrategy(size_t numFields,
const Metadata * const *fieldTypes,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets,
ValueWitnessTable *vwtable) {
auto layout = BasicLayout::initialForValueType();
performBasicLayout(layout, fieldTypes, numFields,
[&](size_t i, const Metadata *fieldType, size_t offset) {
[&](size_t i, const TypeLayout *fieldType, size_t offset) {
fieldOffsets[i] = offset;
});
@@ -1355,11 +1358,10 @@ void swift::swift_initStructMetadata_UniversalStrategy(size_t numFields,
// We have extra inhabitants if the first element does.
// FIXME: generalize this.
if (auto firstFieldVWT = dyn_cast<ExtraInhabitantsValueWitnessTable>(
fieldTypes[0]->getValueWitnesses())) {
if (fieldTypes[0]->flags.hasExtraInhabitants()) {
vwtable->flags = vwtable->flags.withExtraInhabitants(true);
auto xiVWT = cast<ExtraInhabitantsValueWitnessTable>(vwtable);
xiVWT->extraInhabitantFlags = firstFieldVWT->extraInhabitantFlags;
xiVWT->extraInhabitantFlags = fieldTypes[0]->getExtraInhabitantFlags();
// The compiler should already have initialized these.
assert(xiVWT->storeExtraInhabitant);