Skip to content

Commit 5e15d8a

Browse files
authored
Merge pull request #75376 from mikeash/libprespecialize-descriptor-map
[Runtime] Support type descriptor map in LibPrespecialized.
2 parents 68deec2 + 4b3a197 commit 5e15d8a

File tree

8 files changed

+822
-185
lines changed

8 files changed

+822
-185
lines changed

include/swift/Runtime/EnvironmentVariables.h

+12-2
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,24 @@ extern swift::once_t initializeToken;
3030
using string = const char *;
3131

3232
// Declare backing variables.
33-
#define VARIABLE(name, type, defaultValue, help) extern type name ## _variable;
33+
#define VARIABLE(name, type, defaultValue, help) \
34+
extern type name##_variable; \
35+
extern bool name##_isSet_variable;
3436
#include "../../../stdlib/public/runtime/EnvironmentVariables.def"
3537

36-
// Define getter functions.
38+
// Define getter functions. This creates one function with the same name as the
39+
// variable which returns the value set for that variable, and second function
40+
// ending in _isSet which returns a boolean indicating whether the variable was
41+
// set at all, to allow detecting when the variable was explicitly set to the
42+
// same value as the default.
3743
#define VARIABLE(name, type, defaultValue, help) \
3844
inline type name() { \
3945
swift::once(initializeToken, initialize, nullptr); \
4046
return name##_variable; \
47+
} \
48+
inline bool name##_isSet() { \
49+
swift::once(initializeToken, initialize, nullptr); \
50+
return name##_isSet_variable; \
4151
}
4252
#include "../../../stdlib/public/runtime/EnvironmentVariables.def"
4353

include/swift/Runtime/LibPrespecialized.h

+151-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "PrebuiltStringMap.h"
2121
#include "swift/ABI/Metadata.h"
2222
#include "swift/ABI/TargetLayout.h"
23+
#include "swift/Demangling/Demangler.h"
2324

2425
#define LIB_PRESPECIALIZED_TOP_LEVEL_SYMBOL_NAME "_swift_prespecializationsData"
2526

@@ -36,23 +37,44 @@ struct LibPrespecializedData {
3637

3738
typename Runtime::StoredSize optionFlags;
3839

40+
TargetPointer<Runtime, const void> descriptorMap;
41+
3942
// Existing fields are above, add new fields below this point.
4043

44+
// The major/minor version numbers for this version of the struct.
4145
static constexpr uint32_t currentMajorVersion = 1;
42-
static constexpr uint32_t currentMinorVersion = 3;
46+
static constexpr uint32_t currentMinorVersion = 4;
4347

48+
// Version numbers where various fields were introduced.
4449
static constexpr uint32_t minorVersionWithDisabledProcessesTable = 2;
4550
static constexpr uint32_t minorVersionWithPointerKeyedMetadataMap = 3;
4651
static constexpr uint32_t minorVersionWithOptionFlags = 3;
52+
static constexpr uint32_t minorVersionWithDescriptorMap = 4;
4753

4854
// Option flags values.
4955
enum : typename Runtime::StoredSize {
5056
// When this flag is set, the runtime should default to using the
5157
// pointer-keyed table. When not set, default to using the name-keyed table.
5258
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,
5367
};
5468

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+
5678
static bool stringIsNull(const char *str) { return str == nullptr; }
5779

5880
using MetadataMap = PrebuiltStringMap<const char *, Metadata *, stringIsNull>;
@@ -73,18 +95,141 @@ struct LibPrespecializedData {
7395
return pointerKeyedMetadataMap;
7496
}
7597

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);
80106
}
81107
};
82108

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+
83121
const LibPrespecializedData<InProcess> *getLibPrespecializedData();
122+
84123
Metadata *getLibPrespecializedMetadata(const TypeContextDescriptor *description,
85124
const void *const *arguments);
86125
void libPrespecializedImageLoaded();
87126

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+
88233
} // namespace swift
89234

90235
// Validate the prespecialized metadata map by building each entry dynamically

0 commit comments

Comments
 (0)