Skip to content

Commit 5663910

Browse files
committed
Runtime: Add swift_allocateMetadataPack() and swift_allocateWitnessTablePack()
Both return the pack immediately if its already heap allocated, by checking the least significant bit of the pack pointer. Then, - swift_allocateMetadataPack() uniques the metadata pack by the pointer equality of elements. - swift_allocateWitnessTablePack() does not unique the pack. Both return a pack pointer with the least significant bit set, indicating heap allocation.
1 parent 46bf41c commit 5663910

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,36 @@ bool swift_compareProtocolConformanceDescriptors(
444444
const ProtocolConformanceDescriptor *lhs,
445445
const ProtocolConformanceDescriptor *rhs);
446446

447+
/// Allocate a metadata pack on the heap, unless this pack is already on the
448+
/// heap.
449+
///
450+
/// Metadata packs are uniqued by pointer equality on their elements.
451+
///
452+
/// \param pack A pack pointer, where the least significant bit indicates if
453+
/// it is already on the heap.
454+
/// \param count The number of metadata pointers in the pack.
455+
///
456+
/// \returns a metadata pack allocated on the heap, with the least significant
457+
/// bit set to true.
458+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
459+
const Metadata * const *
460+
swift_allocateMetadataPack(const Metadata * const *pack, unsigned count);
461+
462+
/// Allocate a witness table pack on the heap, unless this pack is already on
463+
/// the heap.
464+
///
465+
/// Witness table packs are not uniqued.
466+
///
467+
/// \param pack A pack pointer, where the least significant bit indicates if
468+
/// it is already on the heap.
469+
/// \param count The number of witness table pointers in the pack.
470+
///
471+
/// \returns a witness table pack allocated on the heap, with the least
472+
/// significant bit set to true.
473+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
474+
const WitnessTable * const *
475+
swift_allocateWitnessTablePack(const WitnessTable * const *pack, unsigned count);
476+
447477
/// Fetch a uniqued metadata for a function type.
448478
SWIFT_RUNTIME_EXPORT
449479
const FunctionTypeMetadata *

stdlib/public/runtime/Metadata.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,119 @@ swift::swift_getObjCClassFromMetadataConditional(const Metadata *theMetadata) {
11461146

11471147
#endif
11481148

1149+
/***************************************************************************/
1150+
/*** Metadata and witness table packs **************************************/
1151+
/***************************************************************************/
1152+
1153+
namespace {
1154+
1155+
class MetadataPackCacheEntry {
1156+
public:
1157+
unsigned Count;
1158+
1159+
const Metadata * const * getElements() const {
1160+
return reinterpret_cast<const Metadata * const *>(this + 1);
1161+
}
1162+
1163+
const Metadata ** getElements() {
1164+
return reinterpret_cast<const Metadata **>(this + 1);
1165+
}
1166+
1167+
struct Key {
1168+
const Metadata *const *Data;
1169+
const unsigned Count;
1170+
1171+
unsigned getCount() const {
1172+
return Count;
1173+
}
1174+
1175+
const Metadata *getElement(unsigned index) const {
1176+
assert(index < Count);
1177+
return Data[index];
1178+
}
1179+
1180+
friend llvm::hash_code hash_value(const Key &key) {
1181+
llvm::hash_code hash = 0;
1182+
for (unsigned i = 0; i != key.getCount(); ++i)
1183+
hash = llvm::hash_combine(hash, key.getElement(i));
1184+
return hash;
1185+
}
1186+
};
1187+
1188+
MetadataPackCacheEntry(const Key &key);
1189+
1190+
intptr_t getKeyIntValueForDump() {
1191+
return 0; // No single meaningful value here.
1192+
}
1193+
1194+
bool matchesKey(const Key &key) const {
1195+
if (key.getCount() != Count)
1196+
return false;
1197+
for (unsigned i = 0; i != Count; ++i) {
1198+
if (key.getElement(i) != getElements()[i])
1199+
return false;
1200+
}
1201+
return true;
1202+
}
1203+
1204+
friend llvm::hash_code hash_value(const MetadataPackCacheEntry &value) {
1205+
return hash_value(value.getElements());
1206+
}
1207+
1208+
static size_t getExtraAllocationSize(const Key &key) {
1209+
return getExtraAllocationSize(key.Count);
1210+
}
1211+
1212+
size_t getExtraAllocationSize() const {
1213+
return getExtraAllocationSize(Count);
1214+
}
1215+
1216+
static size_t getExtraAllocationSize(unsigned count) {
1217+
return count * sizeof(const Metadata * const *);
1218+
}
1219+
};
1220+
1221+
MetadataPackCacheEntry::MetadataPackCacheEntry(const Key &key) {
1222+
auto count = key.getCount();
1223+
1224+
for (unsigned i = 0; i < count; ++i)
1225+
getElements()[i] = key.getElement(i);
1226+
}
1227+
1228+
} // end anonymous namespace
1229+
1230+
/// The uniquing structure for metadata packs.
1231+
static SimpleGlobalCache<MetadataPackCacheEntry, MetadataPackTag> MetadataPacks;
1232+
1233+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
1234+
const Metadata * const *
1235+
swift_allocateMetadataPack(const Metadata * const *pack, unsigned count) {
1236+
if (reinterpret_cast<uintptr_t>(pack) & 1)
1237+
return pack;
1238+
1239+
MetadataPackCacheEntry::Key key{pack, count};
1240+
auto bytes = MetadataPacks.getOrInsert(key).first->getElements();
1241+
1242+
uintptr_t bytesWithLSBSet = reinterpret_cast<uintptr_t>(bytes) | 1;
1243+
return reinterpret_cast<const Metadata * const *>(bytesWithLSBSet);
1244+
}
1245+
1246+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
1247+
const WitnessTable * const *
1248+
swift_allocateWitnessTablePack(const WitnessTable * const *pack, unsigned count) {
1249+
if (reinterpret_cast<uintptr_t>(pack) & 1)
1250+
return pack;
1251+
1252+
size_t totalSize = (size_t) count * sizeof(const WitnessTable *);
1253+
1254+
auto bytes = (char*) MetadataAllocator(WitnessTablePackTag)
1255+
.Allocate(totalSize, alignof(const WitnessTable *));
1256+
memcpy(bytes, pack, totalSize);
1257+
1258+
uintptr_t bytesWithLSBSet = reinterpret_cast<uintptr_t>(bytes) | 1;
1259+
return reinterpret_cast<const WitnessTable * const *>(bytesWithLSBSet);
1260+
}
1261+
11491262
/***************************************************************************/
11501263
/*** Functions *************************************************************/
11511264
/***************************************************************************/

stdlib/public/runtime/MetadataAllocatorTags.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,7 @@ TAG(GlobalMetadataCache, 20)
4646
TAG(GlobalWitnessTableCache, 21)
4747
TAG(ExtendedExistentialTypes, 22)
4848
TAG(ExtendedExistentialTypeShapes, 23)
49+
TAG(MetadataPack, 24)
50+
TAG(WitnessTablePack, 25)
4951

5052
#undef TAG

0 commit comments

Comments
 (0)