Skip to content

Commit 32a39b8

Browse files
committed
Simplify the incremental reading of remote descriptors
1 parent 8026475 commit 32a39b8

File tree

1 file changed

+43
-114
lines changed

1 file changed

+43
-114
lines changed

include/swift/Remote/MetadataReader.h

+43-114
Original file line numberDiff line numberDiff line change
@@ -1017,152 +1017,81 @@ class MetadataReader {
10171017
address, reinterpret_cast<const TargetContextDescriptor<Runtime> *>(
10181018
cached->second.get()));
10191019

1020-
// Read the flags to figure out what kind of descriptor this is
1021-
ContextDescriptorFlags flags;
1022-
if (!Reader->readBytes(RemoteAddress(address), (uint8_t*)&flags,
1023-
sizeof(flags))) {
1024-
return nullptr;
1025-
}
1026-
TypeContextDescriptorFlags typeFlags(flags.getKindSpecificFlags());
1027-
uint64_t baseSize = 0;
1028-
uint64_t genericHeaderSize = sizeof(GenericContextDescriptorHeader);
1029-
uint64_t metadataInitSize = 0;
1030-
bool hasVTable = false;
1031-
1032-
auto readMetadataInitSize = [&]() -> unsigned {
1033-
switch (typeFlags.getMetadataInitialization()) {
1034-
case TypeContextDescriptorFlags::NoMetadataInitialization:
1035-
return 0;
1036-
case TypeContextDescriptorFlags::SingletonMetadataInitialization:
1037-
// FIXME: classes
1038-
return sizeof(TargetSingletonMetadataInitialization<Runtime>);
1039-
case TypeContextDescriptorFlags::ForeignMetadataInitialization:
1040-
return sizeof(TargetForeignMetadataInitialization<Runtime>);
1020+
auto buffer = (uint8_t *)nullptr;
1021+
unsigned available = 0; // Size of data in buffer
1022+
1023+
// In the first read, just grab the initial flag value...
1024+
unsigned sizeEstimate = sizeof(ContextDescriptorFlags);
1025+
while (available < sizeEstimate) {
1026+
// The first `available` bytes have already been read, so grow
1027+
// the buffer and read more bytes to fulfill `sizeEstimate`
1028+
auto newbuffer = (uint8_t *)realloc(buffer, sizeEstimate);
1029+
if (!newbuffer) {
1030+
free(buffer);
1031+
return nullptr;
10411032
}
1042-
return 0;
1043-
};
1044-
1045-
// Compute the size of the base object based on the kind of descriptor
1046-
unsigned baseSize = 0;
1047-
switch (auto kind = flags.getKind()) {
1048-
case ContextDescriptorKind::Module:
1049-
baseSize = sizeof(TargetModuleContextDescriptor<Runtime>);
1050-
break;
1051-
case ContextDescriptorKind::Extension:
1052-
baseSize = sizeof(TargetExtensionContextDescriptor<Runtime>);
1053-
break;
1054-
case ContextDescriptorKind::Anonymous:
1055-
baseSize = sizeof(TargetAnonymousContextDescriptor<Runtime>);
1056-
break;
1057-
case ContextDescriptorKind::Class:
1058-
baseSize = sizeof(TargetClassDescriptor<Runtime>);
1059-
break;
1060-
case ContextDescriptorKind::Enum:
1061-
baseSize = sizeof(TargetEnumDescriptor<Runtime>);
1062-
break;
1063-
case ContextDescriptorKind::Struct:
1064-
baseSize = sizeof(TargetStructDescriptor<Runtime>);
1065-
break;
1066-
case ContextDescriptorKind::Protocol:
1067-
baseSize = sizeof(TargetProtocolDescriptor<Runtime>);
1068-
break;
1069-
case ContextDescriptorKind::OpaqueType:
1070-
baseSize = sizeof(TargetOpaqueTypeDescriptor<Runtime>);
1071-
break;
1072-
default:
1073-
// We don't know about this kind of context.
1074-
return nullptr;
1075-
}
1076-
1077-
// We don't know what trailing objects might be present, so
1078-
// round up our initial estimate a bit.
1079-
unsigned sizeEstimate = std::max(baseSize, 128U);
1080-
auto buffer = (uint8_t *)malloc(sizeEstimate);
1081-
unsigned bufferSize = 0; // Size of data in buffer
1082-
1083-
while (true) {
1084-
// Read more of the object
1085-
// The first `bufferSize` bytes have already been read, so just
1086-
// grab the next section to fulfill `sizeEstimate`
1087-
if (!Reader->readBytes(RemoteAddress(address + bufferSize),
1088-
buffer + bufferSize,
1089-
sizeEstimate - bufferSize)) {
1033+
buffer = newbuffer;
1034+
if (!Reader->readBytes(RemoteAddress(address + available),
1035+
buffer + available,
1036+
sizeEstimate - available)) {
10901037
free(buffer);
10911038
return nullptr;
10921039
}
1093-
bufferSize = sizeEstimate;
1094-
// Note that `buffer` includes at least the base object, so
1095-
// it's safe to query the object as long as we don't
1096-
// try to actually access trailing objects that might not exist.
1097-
1098-
// Based on what we have so far, figure out whether we have
1099-
// all the trailing data yet.
1100-
unsigned revisedEstimate = 0;
1040+
available = sizeEstimate;
1041+
1042+
// Based on the data so far, update our guess of the full descriptor size.
1043+
1044+
// All objects start with a flags value, and our first read always gets
1045+
// that much data, so this is safe.
1046+
ContextDescriptorFlags flags;
1047+
memcpy(&flags, buffer, sizeof(flags));
11011048
switch (auto kind = flags.getKind()) {
1102-
// For fixed-size descriptors without trailing data, the baseSize is always correct
1049+
1050+
// Fixed-size descriptors without trailing data have fixed size.
11031051
case ContextDescriptorKind::Module:
1104-
case ContextDescriptorKind::Extension: {
1105-
revisedEstimate = baseSize;
1052+
sizeEstimate = sizeof(TargetModuleContextDescriptor<Runtime>);
11061053
break;
1107-
}
1054+
case ContextDescriptorKind::Extension:
1055+
sizeEstimate = sizeof(TargetExtensionContextDescriptor<Runtime>);
1056+
break;
1057+
11081058
// For types that use trailing objects, ask the trailing object logic to
1109-
// look at what we have so far and tell us whether we're done or not
1059+
// look at what we have so far and tell us whether we're done or not.
11101060
case ContextDescriptorKind::Anonymous: {
1111-
revisedEstimate = TargetAnonymousContextDescriptor<Runtime>::totalSizeOfPartialObject(buffer, bufferSize);
1061+
sizeEstimate = TargetAnonymousContextDescriptor<Runtime>::totalSizeOfPartialObject(buffer, available);
11121062
break;
11131063
}
11141064
case ContextDescriptorKind::Class: {
1115-
revisedEstimate = TargetClassDescriptor<Runtime>::totalSizeOfPartialObject(buffer, bufferSize);
1065+
sizeEstimate = TargetClassDescriptor<Runtime>::totalSizeOfPartialObject(buffer, available);
11161066
break;
11171067
}
11181068
case ContextDescriptorKind::Enum: {
1119-
revisedEstimate = TargetEnumDescriptor<Runtime>::totalSizeOfPartialObject(buffer, bufferSize);
1069+
sizeEstimate = TargetEnumDescriptor<Runtime>::totalSizeOfPartialObject(buffer, available);
11201070
break;
11211071
}
11221072
case ContextDescriptorKind::Struct: {
1123-
revisedEstimate = TargetStructDescriptor<Runtime>::totalSizeOfPartialObject(buffer, bufferSize);
1073+
sizeEstimate = TargetStructDescriptor<Runtime>::totalSizeOfPartialObject(buffer, available);
11241074
break;
11251075
}
11261076
case ContextDescriptorKind::Protocol: {
1127-
revisedEstimate = TargetProtocolDescriptor<Runtime>::totalSizeOfPartialObject(buffer, bufferSize);
1077+
sizeEstimate = TargetProtocolDescriptor<Runtime>::totalSizeOfPartialObject(buffer, available);
11281078
break;
11291079
}
11301080
case ContextDescriptorKind::OpaqueType: {
1131-
revisedEstimate = TargetOpaqueTypeDescriptor<Runtime>::totalSizeOfPartialObject(buffer, bufferSize);
1081+
sizeEstimate = TargetOpaqueTypeDescriptor<Runtime>::totalSizeOfPartialObject(buffer, available);
11321082
break;
11331083
}
1084+
11341085
// We don't know about this kind of context.
11351086
default:
11361087
return nullptr;
11371088
}
1138-
1139-
// If we have everything, then clean up the buffer and exit the loop
1140-
if (revisedEstimate <= bufferSize) {
1141-
auto trueSize = revisedEstimate;
1142-
// If the final true object size is a lot smaller than the allocated
1143-
// buffer, then it's worth a little more work to save memory.
1144-
if (trueSize < bufferSize / 2 && trueSize + 64 < bufferSize) {
1145-
auto newbuffer = (uint8_t *)realloc(buffer, trueSize);
1146-
if (!newbuffer) {
1147-
free(buffer);
1148-
return nullptr;
1149-
}
1150-
buffer = newbuffer;
1151-
}
1152-
bufferSize = trueSize;
1153-
break;
1154-
}
1155-
1156-
// We didn't get everything, increase the working size estimate and try again
1157-
sizeEstimate = std::max(sizeEstimate + 128, revisedEstimate);
1158-
auto newbuffer = (uint8_t *)realloc(buffer, sizeEstimate);
1159-
if (!newbuffer) {
1160-
free(buffer);
1161-
return nullptr;
1162-
}
1163-
buffer = newbuffer;
11641089
}
11651090

1091+
// After exiting loop above, `sizeEstimate` is the true size of the
1092+
// descriptor with all trailing objects and buffer holds at least that much
1093+
// data.
1094+
11661095
// Insert the final object into the descriptor cache and return it
11671096
auto descriptor
11681097
= reinterpret_cast<TargetContextDescriptor<Runtime> *>(buffer);

0 commit comments

Comments
 (0)