32
32
33
33
#include < vector>
34
34
#include < unordered_map>
35
-
35
+ # include < iostream >
36
36
#include < inttypes.h>
37
37
38
38
namespace swift {
@@ -781,9 +781,17 @@ class MetadataReader {
781
781
case MetadataKind::Class:
782
782
return readNominalTypeFromClassMetadata (Meta, skipArtificialSubclasses);
783
783
case MetadataKind::Struct:
784
- case MetadataKind::Enum:
785
784
case MetadataKind::Optional:
786
785
return readNominalTypeFromMetadata (Meta);
786
+ case MetadataKind::Enum: {
787
+ auto d = readNominalTypeFromMetadata (Meta);
788
+ auto enumMeta = cast<TargetEnumMetadata<Runtime>>(Meta);
789
+ // auto hasSpareBits = enumMeta->hasSpareBits();
790
+ // auto spareBitsLength = enumMeta->getEnumSpareBits();
791
+ //
792
+ //
793
+ return d;
794
+ }
787
795
case MetadataKind::Tuple: {
788
796
auto tupleMeta = cast<TargetTupleTypeMetadata<Runtime>>(Meta);
789
797
@@ -1020,24 +1028,36 @@ class MetadataReader {
1020
1028
auto buffer = (uint8_t *)nullptr ;
1021
1029
unsigned available = 0 ; // Size of data in buffer
1022
1030
1023
- // In the first read, just grab the initial flag value...
1024
- unsigned sizeEstimate = sizeof (ContextDescriptorFlags);
1031
+ // We get a big perf win by reading more data initially,
1032
+ // but we don't want to overrun a page. Here's a conservative
1033
+ // guess of how much space is left in the page.
1034
+ unsigned long spaceInPage = 256UL - (address & 0xff );
1035
+
1036
+ // TODO: Some clients (`heap`) map an entire VM region; for
1037
+ // those clients, it would be best to just tell them the
1038
+ // starting remote address and have them tell us the local
1039
+ // address and number of available bytes. That would always
1040
+ // obtain the entire descriptor with a single `readBytes` call.
1041
+
1042
+ // Initial read: At least enough to get all the flags. More if we can.
1043
+ unsigned sizeEstimate = std::max (sizeof (ContextDescriptorFlags), spaceInPage);
1025
1044
while (available < sizeEstimate) {
1026
1045
// 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);
1046
+ // the buffer and read at least enough bytes to fulfill `sizeEstimate`
1047
+ auto newSize = sizeEstimate;
1048
+ auto newbuffer = (uint8_t *)realloc (buffer, newSize);
1029
1049
if (!newbuffer) {
1030
1050
free (buffer);
1031
1051
return nullptr ;
1032
1052
}
1033
1053
buffer = newbuffer;
1034
1054
if (!Reader->readBytes (RemoteAddress (address + available),
1035
1055
buffer + available,
1036
- sizeEstimate - available)) {
1056
+ newSize - available)) {
1037
1057
free (buffer);
1038
1058
return nullptr ;
1039
1059
}
1040
- available = sizeEstimate ;
1060
+ available = newSize ;
1041
1061
1042
1062
// Based on the data so far, update our guess of the full descriptor size.
1043
1063
@@ -1053,7 +1073,7 @@ class MetadataReader {
1053
1073
break ;
1054
1074
1055
1075
// For types that use trailing objects, ask the trailing object logic to
1056
- // look at what we have so far and tell us whether we're done or not .
1076
+ // estimate the total size based on what we have so far .
1057
1077
case ContextDescriptorKind::Extension: {
1058
1078
sizeEstimate = TargetExtensionContextDescriptor<Runtime>::totalSizeOfPartialObject (buffer, available);
1059
1079
break ;
@@ -1085,13 +1105,26 @@ class MetadataReader {
1085
1105
1086
1106
// We don't know about this kind of context.
1087
1107
default :
1108
+ free (buffer);
1088
1109
return nullptr ;
1089
1110
}
1090
1111
}
1091
1112
1092
1113
// After exiting loop above, `sizeEstimate` is the true size of the
1093
- // descriptor with all trailing objects and buffer holds at least that much
1094
- // data.
1114
+ // descriptor with all trailing objects and buffer holds `available` bytes
1115
+ // (which is at least as large as `sizeEstimate`)
1116
+
1117
+ // If we're significantly over-allocated, copy to a more
1118
+ // appropriately-sized buffer.
1119
+ if (sizeEstimate < (available - available / 4 )) {
1120
+ auto newbuffer = (uint8_t *)malloc (sizeEstimate);
1121
+ if (newbuffer != nullptr ) {
1122
+ memcpy (newbuffer, buffer, sizeEstimate);
1123
+ free (buffer);
1124
+ buffer = newbuffer;
1125
+ available = sizeEstimate;
1126
+ }
1127
+ }
1095
1128
1096
1129
// Insert the final object into the descriptor cache and return it
1097
1130
OwnedContextDescriptorRef readResult (buffer);
0 commit comments