20
20
#include " PrebuiltStringMap.h"
21
21
#include " swift/ABI/Metadata.h"
22
22
#include " swift/ABI/TargetLayout.h"
23
+ #include " swift/Demangling/Demangler.h"
23
24
24
25
#define LIB_PRESPECIALIZED_TOP_LEVEL_SYMBOL_NAME " _swift_prespecializationsData"
25
26
@@ -36,23 +37,44 @@ struct LibPrespecializedData {
36
37
37
38
typename Runtime::StoredSize optionFlags;
38
39
40
+ TargetPointer<Runtime, const void > descriptorMap;
41
+
39
42
// Existing fields are above, add new fields below this point.
40
43
44
+ // The major/minor version numbers for this version of the struct.
41
45
static constexpr uint32_t currentMajorVersion = 1 ;
42
- static constexpr uint32_t currentMinorVersion = 3 ;
46
+ static constexpr uint32_t currentMinorVersion = 4 ;
43
47
48
+ // Version numbers where various fields were introduced.
44
49
static constexpr uint32_t minorVersionWithDisabledProcessesTable = 2 ;
45
50
static constexpr uint32_t minorVersionWithPointerKeyedMetadataMap = 3 ;
46
51
static constexpr uint32_t minorVersionWithOptionFlags = 3 ;
52
+ static constexpr uint32_t minorVersionWithDescriptorMap = 4 ;
47
53
48
54
// Option flags values.
49
55
enum : typename Runtime::StoredSize {
50
56
// When this flag is set, the runtime should default to using the
51
57
// pointer-keyed table. When not set, default to using the name-keyed table.
52
58
OptionFlagDefaultToPointerKeyedMap = 1ULL << 0 ,
59
+
60
+ // When this flag is set, the runtime should default to using the descriptor
61
+ // map. When not set, default to turning off the descriptor map.
62
+ OptionFlagDescriptorMapDefaultOn = 1ULL << 1 ,
63
+
64
+ // When this flag is set, descriptorMap is not comprehensive, meaning that
65
+ // a negative lookup result is not a definitive failure.
66
+ OptionFlagDescriptorMapNotComprehensive = 1ULL << 2 ,
53
67
};
54
68
55
- // Helpers for retrieving the metadata map in-process.
69
+ // Helpers for safely retrieving various fields. Helpers return 0 or NULL if
70
+ // the version number indicates that the field is not present.
71
+
72
+ typename Runtime::StoredSize getOptionFlags () const {
73
+ if (minorVersion < minorVersionWithOptionFlags)
74
+ return 0 ;
75
+ return optionFlags;
76
+ }
77
+
56
78
static bool stringIsNull (const char *str) { return str == nullptr ; }
57
79
58
80
using MetadataMap = PrebuiltStringMap<const char *, Metadata *, stringIsNull>;
@@ -73,18 +95,141 @@ struct LibPrespecializedData {
73
95
return pointerKeyedMetadataMap;
74
96
}
75
97
76
- typename Runtime::StoredSize getOptionFlags () const {
77
- if (minorVersion < minorVersionWithOptionFlags)
78
- return 0 ;
79
- return optionFlags;
98
+ using DescriptorMap =
99
+ PrebuiltAuxDataImplicitStringMap<TargetPointer<Runtime, const void >,
100
+ uint16_t >;
101
+
102
+ const DescriptorMap *getDescriptorMap () const {
103
+ if (minorVersion < minorVersionWithDescriptorMap)
104
+ return nullptr ;
105
+ return reinterpret_cast <const DescriptorMap *>(descriptorMap);
80
106
}
81
107
};
82
108
109
+ enum class LibPrespecializedLookupResult {
110
+ // We found something.
111
+ Found,
112
+
113
+ // We didn't find anything, and we know it's not in the shared cache.
114
+ DefinitiveNotFound,
115
+
116
+ // We didn't find anything, but we couldn't rule out the shared cache. Caller
117
+ // must do a full search.
118
+ NonDefinitiveNotFound,
119
+ };
120
+
83
121
const LibPrespecializedData<InProcess> *getLibPrespecializedData ();
122
+
84
123
Metadata *getLibPrespecializedMetadata (const TypeContextDescriptor *description,
85
124
const void *const *arguments);
86
125
void libPrespecializedImageLoaded ();
87
126
127
+ std::pair<LibPrespecializedLookupResult, const TypeContextDescriptor *>
128
+ getLibPrespecializedTypeDescriptor (Demangle::NodePointer node);
129
+
130
+ // / Given the demangling referring to a particular descriptor, build the
131
+ // / canonical simplified version of the demangling that's used for the keys in
132
+ // / the descriptorMap. We copy across Extension and Module nodes. Type nodes are
133
+ // / all normalized to be OtherNominalType to allow for the runtime allowing
134
+ // / type kind mismatches on imported C types in certain cases. Other nodes are
135
+ // / skipped.
136
+ // /
137
+ // / The runtime always searches through duplicates in the table, and uses its
138
+ // / own matching on all candidates, so the simplified demangling is allowed to
139
+ // / be simplified to the point of having different descriptors sometimes produce
140
+ // / the same demangling.
141
+ static inline Demangle::NodePointer
142
+ buildSimplifiedDescriptorDemangling (Demangle::NodePointer node,
143
+ Demangle::Demangler &dem) {
144
+ // The node that will be returned to the caller.
145
+ Demangle::NodePointer result = nullptr ;
146
+
147
+ // The bottommost node in the result that we've generated. Additional nodes
148
+ // are added as children to this one.
149
+ Demangle::NodePointer resultBottom = nullptr ;
150
+
151
+ // The current node that we're iterating over in the input node tree.
152
+ Demangle::NodePointer current = node;
153
+
154
+ using Kind = Demangle::Node::Kind;
155
+
156
+ // Helper to add a new node to the result. This sets `result` to the node if
157
+ // it hasn't already been set (indicating this is the topmost node), and adds
158
+ // the node as a child to `resultBottom` otherwise. `resultBottom` is updated
159
+ // to point to the new node.
160
+ auto addNode = [&](Demangle::NodePointer newNode) {
161
+ if (!result) {
162
+ result = newNode;
163
+ } else {
164
+ if (resultBottom->getKind () == Kind::Extension) {
165
+ resultBottom->addChild (newNode, dem);
166
+ } else {
167
+ // Shift the Identifier down, insert before it.
168
+ resultBottom->addChild (resultBottom->getFirstChild (), dem);
169
+ resultBottom->replaceChild (0 , newNode);
170
+ }
171
+ }
172
+ resultBottom = newNode;
173
+ };
174
+
175
+ // Walk down the input node tree.
176
+ while (current) {
177
+ switch (current->getKind ()) {
178
+ case Kind::Extension: {
179
+ // Extensions are copied across. The new extension node has the module
180
+ // from the original, and the second child will be added as we traverse
181
+ // the next node in the tree.
182
+ auto copy = dem.createNode (Kind::Extension);
183
+ auto module = current->getChild (0 );
184
+ if (module == nullptr || module->getKind () != Kind::Module)
185
+ return nullptr ;
186
+ copy->addChild (module, dem);
187
+ addNode (copy);
188
+ current = current->getChild (1 );
189
+ break ;
190
+ }
191
+ case Kind::Module: {
192
+ // Module contents are always in the form we want, so we can incorporate
193
+ // this node verbatim and terminate the walk.
194
+ addNode (current);
195
+ current = nullptr ;
196
+ break ;
197
+ }
198
+ case Kind::Protocol: {
199
+ // Bring Protocol nodes across verbatim, there's no fuzzy matching.
200
+ addNode (current);
201
+ current = nullptr ;
202
+ break ;
203
+ }
204
+ case Kind::OpaqueType:
205
+ case Kind::Class:
206
+ case Kind::Structure:
207
+ case Kind::Enum:
208
+ case Kind::TypeAlias:
209
+ case Kind::OtherNominalType: {
210
+ // Type nodes are copied across with the kind always set to
211
+ // OtherNominalType.
212
+ auto copy = dem.createNode (Kind::OtherNominalType);
213
+ auto identifier = current->getChild (1 );
214
+ if (identifier == nullptr || identifier->getKind () != Kind::Identifier)
215
+ return nullptr ;
216
+ copy->addChild (identifier, dem);
217
+ addNode (copy);
218
+ current = current->getChild (0 );
219
+ break ;
220
+ }
221
+
222
+ default :
223
+ // If we don't know about this node, continue the walk with its first
224
+ // child.
225
+ current = current->getFirstChild ();
226
+ break ;
227
+ }
228
+ }
229
+
230
+ return result;
231
+ }
232
+
88
233
} // namespace swift
89
234
90
235
// Validate the prespecialized metadata map by building each entry dynamically
0 commit comments