@@ -1017,152 +1017,81 @@ class MetadataReader {
1017
1017
address, reinterpret_cast <const TargetContextDescriptor<Runtime> *>(
1018
1018
cached->second .get ()));
1019
1019
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 ;
1041
1032
}
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)) {
1090
1037
free (buffer);
1091
1038
return nullptr ;
1092
1039
}
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)) ;
1101
1048
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.
1103
1051
case ContextDescriptorKind::Module:
1104
- case ContextDescriptorKind::Extension: {
1105
- revisedEstimate = baseSize;
1052
+ sizeEstimate = sizeof (TargetModuleContextDescriptor<Runtime>);
1106
1053
break ;
1107
- }
1054
+ case ContextDescriptorKind::Extension:
1055
+ sizeEstimate = sizeof (TargetExtensionContextDescriptor<Runtime>);
1056
+ break ;
1057
+
1108
1058
// 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.
1110
1060
case ContextDescriptorKind::Anonymous: {
1111
- revisedEstimate = TargetAnonymousContextDescriptor<Runtime>::totalSizeOfPartialObject (buffer, bufferSize );
1061
+ sizeEstimate = TargetAnonymousContextDescriptor<Runtime>::totalSizeOfPartialObject (buffer, available );
1112
1062
break ;
1113
1063
}
1114
1064
case ContextDescriptorKind::Class: {
1115
- revisedEstimate = TargetClassDescriptor<Runtime>::totalSizeOfPartialObject (buffer, bufferSize );
1065
+ sizeEstimate = TargetClassDescriptor<Runtime>::totalSizeOfPartialObject (buffer, available );
1116
1066
break ;
1117
1067
}
1118
1068
case ContextDescriptorKind::Enum: {
1119
- revisedEstimate = TargetEnumDescriptor<Runtime>::totalSizeOfPartialObject (buffer, bufferSize );
1069
+ sizeEstimate = TargetEnumDescriptor<Runtime>::totalSizeOfPartialObject (buffer, available );
1120
1070
break ;
1121
1071
}
1122
1072
case ContextDescriptorKind::Struct: {
1123
- revisedEstimate = TargetStructDescriptor<Runtime>::totalSizeOfPartialObject (buffer, bufferSize );
1073
+ sizeEstimate = TargetStructDescriptor<Runtime>::totalSizeOfPartialObject (buffer, available );
1124
1074
break ;
1125
1075
}
1126
1076
case ContextDescriptorKind::Protocol: {
1127
- revisedEstimate = TargetProtocolDescriptor<Runtime>::totalSizeOfPartialObject (buffer, bufferSize );
1077
+ sizeEstimate = TargetProtocolDescriptor<Runtime>::totalSizeOfPartialObject (buffer, available );
1128
1078
break ;
1129
1079
}
1130
1080
case ContextDescriptorKind::OpaqueType: {
1131
- revisedEstimate = TargetOpaqueTypeDescriptor<Runtime>::totalSizeOfPartialObject (buffer, bufferSize );
1081
+ sizeEstimate = TargetOpaqueTypeDescriptor<Runtime>::totalSizeOfPartialObject (buffer, available );
1132
1082
break ;
1133
1083
}
1084
+
1134
1085
// We don't know about this kind of context.
1135
1086
default :
1136
1087
return nullptr ;
1137
1088
}
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;
1164
1089
}
1165
1090
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
+
1166
1095
// Insert the final object into the descriptor cache and return it
1167
1096
auto descriptor
1168
1097
= reinterpret_cast <TargetContextDescriptor<Runtime> *>(buffer);
0 commit comments