Skip to content

Commit 58ff42a

Browse files
authored
[Runtime] Properly handle tuple types in layout string instantiation (#66603)
Tuple types contain metadata entries for each element, so we can handle them individually to avoid unnecessary indirection.
1 parent 7143203 commit 58ff42a

File tree

4 files changed

+146
-158
lines changed

4 files changed

+146
-158
lines changed

include/swift/Runtime/Metadata.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -666,9 +666,6 @@ void swift_initStructMetadataWithLayoutString(StructMetadata *self,
666666
const uint8_t *fieldTags,
667667
uint32_t *fieldOffsets);
668668

669-
SWIFT_RUNTIME_STDLIB_INTERNAL
670-
size_t _swift_refCountBytesForMetatype(const Metadata *type);
671-
672669
enum LayoutStringFlags : uint64_t {
673670
Empty = 0,
674671
// TODO: Track other useful information tha can be used to optimize layout
@@ -688,6 +685,9 @@ inline LayoutStringFlags &operator|=(LayoutStringFlags &a, LayoutStringFlags b)
688685
return a = (a | b);
689686
}
690687

688+
SWIFT_RUNTIME_STDLIB_INTERNAL
689+
size_t _swift_refCountBytesForMetatype(const Metadata *type);
690+
691691
SWIFT_RUNTIME_STDLIB_INTERNAL
692692
void _swift_addRefCountStringForMetatype(uint8_t *layoutStr,
693693
size_t &layoutStrOffset,

stdlib/public/runtime/BytecodeLayouts.cpp

-20
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,6 @@
3737

3838
using namespace swift;
3939

40-
static const size_t layoutStringHeaderSize = sizeof(uint64_t) + sizeof(size_t);
41-
42-
/// Given a pointer and an offset, read the requested data and increment the
43-
/// offset
44-
template <typename T>
45-
static T readBytes(const uint8_t *typeLayout, size_t &i) {
46-
T returnVal;
47-
memcpy(&returnVal, typeLayout + i, sizeof(T));
48-
i += sizeof(T);
49-
return returnVal;
50-
}
51-
52-
/// Given a pointer, a value, and an offset, write the value at the given
53-
/// offset and increment offset by the size of T
54-
template <typename T>
55-
static void writeBytes(uint8_t *typeLayout, size_t &i, T value) {
56-
memcpy(typeLayout + i, &value, sizeof(T));
57-
i += sizeof(T);
58-
}
59-
6040
static Metadata *getExistentialTypeMetadata(OpaqueValue *object) {
6141
return reinterpret_cast<Metadata**>(object)[NumWords_ValueBuffer];
6242
}

stdlib/public/runtime/BytecodeLayouts.h

+17
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,23 @@ void swift_resolve_resilientAccessors(uint8_t *layoutStr,
7373
size_t layoutStrOffset,
7474
const uint8_t *fieldLayoutStr,
7575
const Metadata *fieldType);
76+
77+
template <typename T>
78+
inline T readBytes(const uint8_t *layoutStr, size_t &i) {
79+
T returnVal;
80+
memcpy(&returnVal, layoutStr + i, sizeof(T));
81+
i += sizeof(T);
82+
return returnVal;
83+
}
84+
85+
template <typename T>
86+
inline void writeBytes(uint8_t *layoutStr, size_t &i, T value) {
87+
memcpy(layoutStr + i, &value, sizeof(T));
88+
i += sizeof(T);
89+
}
90+
91+
constexpr size_t layoutStringHeaderSize = sizeof(uint64_t) + sizeof(size_t);
92+
7693
} // namespace swift
7794

7895
#endif // SWIFT_BYTECODE_LAYOUTS_H

stdlib/public/runtime/Metadata.cpp

+126-135
Original file line numberDiff line numberDiff line change
@@ -2641,41 +2641,6 @@ void swift::swift_initStructMetadata(StructMetadata *structType,
26412641
vwtable->publishLayout(layout);
26422642
}
26432643

2644-
namespace {
2645-
enum LayoutStringFlags : uint64_t {
2646-
Empty = 0,
2647-
// TODO: Track other useful information tha can be used to optimize layout
2648-
// strings, like different reference kinds contained in the string
2649-
// number of ref counting operations (maybe up to 4), so we can
2650-
// use witness functions optimized for these cases.
2651-
HasRelativePointers = (1ULL << 63),
2652-
};
2653-
2654-
inline bool operator&(LayoutStringFlags a, LayoutStringFlags b) {
2655-
return (uint64_t(a) & uint64_t(b)) != 0;
2656-
}
2657-
inline LayoutStringFlags operator|(LayoutStringFlags a, LayoutStringFlags b) {
2658-
return LayoutStringFlags(uint64_t(a) | uint64_t(b));
2659-
}
2660-
inline LayoutStringFlags &operator|=(LayoutStringFlags &a, LayoutStringFlags b) {
2661-
return a = (a | b);
2662-
}
2663-
2664-
template <typename T>
2665-
inline T readBytes(const uint8_t *layoutStr, size_t &i) {
2666-
T returnVal;
2667-
memcpy(&returnVal, layoutStr + i, sizeof(T));
2668-
i += sizeof(T);
2669-
return returnVal;
2670-
}
2671-
2672-
template <typename T>
2673-
inline void writeBytes(uint8_t *layoutStr, size_t &i, T value) {
2674-
memcpy(layoutStr + i, &value, sizeof(T));
2675-
i += sizeof(T);
2676-
}
2677-
} // end anonymous namespace
2678-
26792644
void swift::swift_initStructMetadataWithLayoutString(
26802645
StructMetadata *structType, StructLayoutFlags layoutFlags, size_t numFields,
26812646
const uint8_t *const *fieldTypes, const uint8_t *fieldTags,
@@ -2727,21 +2692,9 @@ void swift::swift_initStructMetadataWithLayoutString(
27272692
extraInhabitantCount = fieldExtraInhabitantCount;
27282693
}
27292694

2730-
if (fieldType->vw_size() == 0) {
2731-
continue;
2732-
} else if (fieldType->getValueWitnesses()->isPOD()) {
2733-
// no extra space required for POD
2734-
} else if (fieldType->hasLayoutString()) {
2735-
refCountBytes += *(const size_t *)(fieldType->getLayoutString() +
2736-
sizeof(uint64_t));
2737-
} else if (fieldType->isClassObject() || fieldType->isAnyExistentialType()) {
2738-
refCountBytes += sizeof(uint64_t);
2739-
} else {
2740-
refCountBytes += sizeof(uint64_t) + sizeof(uintptr_t);
2741-
}
2695+
refCountBytes += _swift_refCountBytesForMetatype(fieldType);
27422696
}
27432697

2744-
const size_t layoutStringHeaderSize = sizeof(uint64_t) + sizeof(size_t);
27452698
const size_t fixedLayoutStringSize = layoutStringHeaderSize +
27462699
sizeof(uint64_t) * 2;
27472700

@@ -2781,93 +2734,9 @@ void swift::swift_initStructMetadataWithLayoutString(
27812734

27822735
const Metadata *fieldType = (const Metadata*)fieldTypes[i];
27832736

2784-
fullOffset = roundUpToAlignMask(fullOffset, fieldType->vw_alignment() - 1);
2785-
size_t offset = fullOffset - unalignedOffset + previousFieldOffset;
2786-
2787-
if (fieldType->vw_size() == 0) {
2788-
continue;
2789-
} else if (fieldType->getValueWitnesses()->isPOD()) {
2790-
// No need to handle PODs
2791-
previousFieldOffset = offset + fieldType->vw_size();
2792-
fullOffset += fieldType->vw_size();
2793-
} else if (fieldType->hasLayoutString()) {
2794-
const uint8_t *fieldLayoutStr = fieldType->getLayoutString();
2795-
const LayoutStringFlags fieldFlags =
2796-
*(const LayoutStringFlags *)fieldLayoutStr;
2797-
const size_t fieldRefCountBytes =
2798-
*(const size_t *)(fieldLayoutStr + sizeof(uint64_t));
2799-
if (fieldRefCountBytes > 0) {
2800-
flags |= fieldFlags;
2801-
memcpy(layoutStr + layoutStrOffset, fieldLayoutStr + layoutStringHeaderSize,
2802-
fieldRefCountBytes);
2803-
2804-
if (fieldFlags & LayoutStringFlags::HasRelativePointers) {
2805-
swift_resolve_resilientAccessors(layoutStr, layoutStrOffset,
2806-
fieldLayoutStr, fieldType);
2807-
}
2808-
2809-
if (offset) {
2810-
auto layoutStrOffsetCopy = layoutStrOffset;
2811-
auto firstTagAndOffset =
2812-
readBytes<uint64_t>(layoutStr, layoutStrOffsetCopy);
2813-
layoutStrOffsetCopy = layoutStrOffset;
2814-
firstTagAndOffset += offset;
2815-
writeBytes(layoutStr, layoutStrOffsetCopy, firstTagAndOffset);
2816-
}
2817-
2818-
auto previousFieldOffsetOffset =
2819-
layoutStringHeaderSize + fieldRefCountBytes;
2820-
previousFieldOffset = readBytes<uint64_t>(fieldLayoutStr,
2821-
previousFieldOffsetOffset);
2822-
layoutStrOffset += fieldRefCountBytes;
2823-
} else {
2824-
previousFieldOffset += fieldType->vw_size();
2825-
}
2826-
fullOffset += fieldType->vw_size();
2827-
} else if (auto *cls = fieldType->getClassObject()) {
2828-
RefCountingKind tag;
2829-
if (!cls->isTypeMetadata()) {
2830-
#if SWIFT_OBJC_INTEROP
2831-
tag = RefCountingKind::ObjC;
2832-
#else
2833-
tag = RefCountingKind::Unknown;
2834-
#endif
2835-
} else {
2836-
auto *vwt = cls->getValueWitnesses();
2837-
if (vwt == &VALUE_WITNESS_SYM(Bo)) {
2838-
tag = RefCountingKind::NativeStrong;
2839-
} else if (vwt == &VALUE_WITNESS_SYM(BO)) {
2840-
#if SWIFT_OBJC_INTEROP
2841-
tag = RefCountingKind::ObjC;
2842-
#else
2843-
tag = RefCountingKind::Unknown;
2844-
#endif
2845-
} else if (vwt == &VALUE_WITNESS_SYM(Bb)) {
2846-
tag = RefCountingKind::Bridge;
2847-
} else {
2848-
goto metadata;
2849-
};
2850-
}
2851-
2852-
writeBytes(layoutStr, layoutStrOffset, ((uint64_t)tag << 56) | offset);
2853-
previousFieldOffset = fieldType->vw_size();
2854-
fullOffset += previousFieldOffset;
2855-
} else if (fieldType->isAnyExistentialType()) {
2856-
auto *existential = dyn_cast<ExistentialTypeMetadata>(fieldType);
2857-
assert(existential);
2858-
auto tag = existential->isClassBounded() ? RefCountingKind::Unknown
2859-
: RefCountingKind::Existential;
2860-
writeBytes(layoutStr, layoutStrOffset, ((uint64_t)tag << 56) | offset);
2861-
previousFieldOffset = fieldType->vw_size();
2862-
fullOffset += previousFieldOffset;
2863-
} else {
2864-
metadata:
2865-
writeBytes(layoutStr, layoutStrOffset,
2866-
((uint64_t)RefCountingKind::Metatype << 56) | offset);
2867-
writeBytes(layoutStr, layoutStrOffset, fieldType);
2868-
previousFieldOffset = fieldType->vw_size();
2869-
fullOffset += previousFieldOffset;
2870-
}
2737+
_swift_addRefCountStringForMetatype(layoutStr, layoutStrOffset, flags,
2738+
fieldType, fullOffset,
2739+
previousFieldOffset);
28712740
}
28722741

28732742
writeBytes(layoutStr, layoutStrOffset, previousFieldOffset);
@@ -2896,6 +2765,128 @@ void swift::swift_initStructMetadataWithLayoutString(
28962765
vwtable->publishLayout(layout);
28972766
}
28982767

2768+
size_t swift::_swift_refCountBytesForMetatype(const Metadata *type) {
2769+
if (type->vw_size() == 0 || type->getValueWitnesses()->isPOD()) {
2770+
return 0;
2771+
} else if (type->hasLayoutString()) {
2772+
size_t offset = sizeof(uint64_t);
2773+
return readBytes<size_t>(type->getLayoutString(), offset);
2774+
} else if (type->isClassObject() || type->isAnyExistentialType()) {
2775+
return sizeof(uint64_t);
2776+
} else if (auto *tuple = dyn_cast<TupleTypeMetadata>(type)) {
2777+
size_t res = 0;
2778+
for (InProcess::StoredSize i = 0; i < tuple->NumElements; i++) {
2779+
res += _swift_refCountBytesForMetatype(tuple->getElement(i).Type);
2780+
}
2781+
return res;
2782+
} else {
2783+
return sizeof(uint64_t) + sizeof(uintptr_t);
2784+
}
2785+
}
2786+
2787+
void swift::_swift_addRefCountStringForMetatype(uint8_t *layoutStr,
2788+
size_t &layoutStrOffset,
2789+
LayoutStringFlags &flags,
2790+
const Metadata *fieldType,
2791+
size_t &fullOffset,
2792+
size_t &previousFieldOffset) {
2793+
size_t unalignedOffset = fullOffset;
2794+
fullOffset = roundUpToAlignMask(fullOffset, fieldType->vw_alignment() - 1);
2795+
size_t offset = fullOffset - unalignedOffset + previousFieldOffset;
2796+
if (fieldType->vw_size() == 0) {
2797+
return;
2798+
} else if (fieldType->getValueWitnesses()->isPOD()) {
2799+
// No need to handle PODs
2800+
previousFieldOffset = offset + fieldType->vw_size();
2801+
fullOffset += fieldType->vw_size();
2802+
} else if (fieldType->hasLayoutString()) {
2803+
const uint8_t *fieldLayoutStr = fieldType->getLayoutString();
2804+
const LayoutStringFlags fieldFlags =
2805+
*(const LayoutStringFlags *)fieldLayoutStr;
2806+
size_t refCountBytesOffset = sizeof(uint64_t);
2807+
const size_t fieldRefCountBytes = readBytes<size_t>(fieldLayoutStr,
2808+
refCountBytesOffset);
2809+
if (fieldRefCountBytes > 0) {
2810+
flags |= fieldFlags;
2811+
memcpy(layoutStr + layoutStrOffset,
2812+
fieldLayoutStr + layoutStringHeaderSize,
2813+
fieldRefCountBytes);
2814+
2815+
if (fieldFlags & LayoutStringFlags::HasRelativePointers) {
2816+
swift_resolve_resilientAccessors(layoutStr, layoutStrOffset,
2817+
fieldLayoutStr, fieldType);
2818+
}
2819+
2820+
if (offset) {
2821+
auto layoutStrOffsetCopy = layoutStrOffset;
2822+
auto firstTagAndOffset =
2823+
readBytes<uint64_t>(layoutStr, layoutStrOffsetCopy);
2824+
layoutStrOffsetCopy = layoutStrOffset;
2825+
firstTagAndOffset += offset;
2826+
writeBytes(layoutStr, layoutStrOffsetCopy, firstTagAndOffset);
2827+
}
2828+
2829+
auto previousFieldOffsetOffset =
2830+
layoutStringHeaderSize + fieldRefCountBytes;
2831+
previousFieldOffset = readBytes<uint64_t>(fieldLayoutStr,
2832+
previousFieldOffsetOffset);
2833+
layoutStrOffset += fieldRefCountBytes;
2834+
} else {
2835+
previousFieldOffset += fieldType->vw_size();
2836+
}
2837+
fullOffset += fieldType->vw_size();
2838+
} else if (auto *tuple = dyn_cast<TupleTypeMetadata>(fieldType)) {
2839+
for (InProcess::StoredSize i = 0; i < tuple->NumElements; i++) {
2840+
_swift_addRefCountStringForMetatype(layoutStr, layoutStrOffset, flags,
2841+
tuple->getElement(i).Type, fullOffset,
2842+
previousFieldOffset);
2843+
}
2844+
} else if (auto *cls = fieldType->getClassObject()) {
2845+
RefCountingKind tag;
2846+
if (!cls->isTypeMetadata()) {
2847+
#if SWIFT_OBJC_INTEROP
2848+
tag = RefCountingKind::ObjC;
2849+
#else
2850+
tag = RefCountingKind::Unknown;
2851+
#endif
2852+
} else {
2853+
auto *vwt = cls->getValueWitnesses();
2854+
if (vwt == &VALUE_WITNESS_SYM(Bo)) {
2855+
tag = RefCountingKind::NativeStrong;
2856+
} else if (vwt == &VALUE_WITNESS_SYM(BO)) {
2857+
#if SWIFT_OBJC_INTEROP
2858+
tag = RefCountingKind::ObjC;
2859+
#else
2860+
tag = RefCountingKind::Unknown;
2861+
#endif
2862+
} else if (vwt == &VALUE_WITNESS_SYM(Bb)) {
2863+
tag = RefCountingKind::Bridge;
2864+
} else {
2865+
goto metadata;
2866+
};
2867+
}
2868+
2869+
writeBytes(layoutStr, layoutStrOffset, ((uint64_t)tag << 56) | offset);
2870+
previousFieldOffset = fieldType->vw_size();
2871+
fullOffset += previousFieldOffset;
2872+
} else if (fieldType->isAnyExistentialType()) {
2873+
auto *existential = dyn_cast<ExistentialTypeMetadata>(fieldType);
2874+
assert(existential);
2875+
auto tag = existential->isClassBounded() ? RefCountingKind::Unknown
2876+
: RefCountingKind::Existential;
2877+
writeBytes(layoutStr, layoutStrOffset, ((uint64_t)tag << 56) | offset);
2878+
previousFieldOffset = fieldType->vw_size();
2879+
fullOffset += previousFieldOffset;
2880+
} else {
2881+
metadata:
2882+
writeBytes(layoutStr, layoutStrOffset,
2883+
((uint64_t)RefCountingKind::Metatype << 56) | offset);
2884+
writeBytes(layoutStr, layoutStrOffset, fieldType);
2885+
previousFieldOffset = fieldType->vw_size();
2886+
fullOffset += previousFieldOffset;
2887+
}
2888+
}
2889+
28992890
/***************************************************************************/
29002891
/*** Classes ***************************************************************/
29012892
/***************************************************************************/

0 commit comments

Comments
 (0)