Skip to content

Commit f28d1d8

Browse files
committed
[Static Mirror] Handle anonymous contexts when re-constructing fully-qualified type names
Anonymous contexts (e.g. types nested inside functons) require special handling when we are constructing a fully-qualified name. We construct the name by walking from a type's descriptor to its parent contexts. Previously, we would give up upon encountering an anonymous contexts. This change refactors fully-qualified name construction to happen in two phases: 1. Collect a full context ancestor chain 2. Walk the chain backwards to reconstruct the fully-qualified name As opposed to the previous approach which always constructed the name while recursively walking to the parent context. This is required because types nested inside anonymous contexts are represented in the fully-qualified type name as `(type_name in $XXXXXXXX)` where XXXXXXXX is the address of the context descriptor of the parent anonymous context. Resolves rdar://91073103
1 parent 07ffdde commit f28d1d8

File tree

4 files changed

+209
-96
lines changed

4 files changed

+209
-96
lines changed

include/swift/ABI/Metadata.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2839,6 +2839,9 @@ struct TargetAnonymousContextDescriptor final
28392839
};
28402840
using AnonymousContextDescriptor = TargetAnonymousContextDescriptor<InProcess>;
28412841

2842+
template<template <typename Runtime> class ObjCInteropKind, unsigned PointerSize>
2843+
using ExternalAnonymousContextDescriptor = TargetAnonymousContextDescriptor<External<ObjCInteropKind<RuntimeTarget<PointerSize>>>>;
2844+
28422845
/// A protocol descriptor.
28432846
///
28442847
/// Protocol descriptors contain information about the contents of a protocol:

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 198 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <iomanip>
2828
#include <iostream>
2929
#include <ostream>
30+
#include <sstream>
3031
#include <unordered_map>
3132
#include <vector>
3233

@@ -1027,88 +1028,111 @@ class TypeRefBuilder {
10271028
OpaqueStringReader(stringReader), OpaquePointerReader(pointerReader) {
10281029
}
10291030

1030-
llvm::Optional<std::string>
1031-
getParentContextName(uintptr_t contextDescriptorAddress) {
1032-
llvm::Optional<std::string> optionalParentContextName;
1033-
auto contextTypeDescriptorBytes = OpaqueByteReader(
1034-
remote::RemoteAddress(contextDescriptorAddress),
1035-
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
1036-
if (!contextTypeDescriptorBytes.get()) {
1037-
Error = "Failed to read context descriptor.";
1038-
return llvm::None;
1039-
}
1040-
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1041-
*contextDescriptor =
1042-
(const ExternalContextDescriptor<ObjCInteropKind, PointerSize> *)
1043-
contextTypeDescriptorBytes.get();
1031+
struct ContextNameInfo {
1032+
std::string name;
1033+
uintptr_t descriptorAddress;
1034+
bool isAnonymous;
1035+
1036+
~ContextNameInfo() {}
1037+
};
1038+
1039+
bool isModuleDescriptor(
1040+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1041+
*contextDescriptor) {
1042+
return isa<ExternalModuleContextDescriptor<ObjCInteropKind, PointerSize>>(
1043+
contextDescriptor);
1044+
}
10441045

1046+
uintptr_t getParentDescriptorAddress(
1047+
uintptr_t contextDescriptorAddress,
1048+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1049+
*contextDescriptor) {
10451050
auto parentOffsetAddress = detail::applyRelativeOffset(
10461051
(const char *)contextDescriptorAddress,
10471052
(int32_t)contextDescriptor->getParentOffset());
1048-
auto parentOffsetBytes = OpaqueByteReader(
1053+
auto parentOfsetBytes = OpaqueByteReader(
10491054
remote::RemoteAddress(parentOffsetAddress), sizeof(uint32_t));
1050-
if (!parentOffsetBytes.get()) {
1051-
Error = "Failed to parent offset in a type descriptor.";
1052-
return llvm::None;
1053-
}
1054-
auto parentFieldOffset = (const int32_t *)parentOffsetBytes.get();
1055+
auto parentFieldOffset = (const int32_t *)parentOfsetBytes.get();
10551056
auto parentTargetAddress = detail::applyRelativeOffset(
10561057
(const char *)parentOffsetAddress, *parentFieldOffset);
1058+
return parentTargetAddress;
1059+
}
10571060

1058-
//
1059-
auto readContextParentName =
1060-
[&](uintptr_t descriptorAddress) -> llvm::Optional<std::string> {
1061-
llvm::Optional<std::string> optionalParentName;
1061+
llvm::Optional<ContextNameInfo>
1062+
getContextName(uintptr_t contextDescriptorAddress,
1063+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1064+
*contextDescriptor) {
1065+
if (auto moduleDescriptor = dyn_cast<
1066+
ExternalModuleContextDescriptor<ObjCInteropKind, PointerSize>>(
1067+
contextDescriptor)) {
1068+
auto moduleDescriptorName = readModuleNameFromModuleDescriptor(
1069+
moduleDescriptor, contextDescriptorAddress);
1070+
if (!moduleDescriptorName.hasValue())
1071+
return llvm::None;
1072+
else
1073+
return ContextNameInfo{moduleDescriptorName.getValue(),
1074+
contextDescriptorAddress, false};
1075+
} else if (auto typeDescriptor = dyn_cast<ExternalTypeContextDescriptor<
1076+
ObjCInteropKind, PointerSize>>(contextDescriptor)) {
1077+
auto typeDescriptorName = readTypeNameFromTypeDescriptor(
1078+
typeDescriptor, contextDescriptorAddress);
1079+
if (!typeDescriptorName.hasValue())
1080+
return llvm::None;
1081+
else
1082+
return ContextNameInfo{typeDescriptorName.getValue(),
1083+
contextDescriptorAddress, false};
1084+
} else if (auto anonymousDescriptor =
1085+
dyn_cast<ExternalAnonymousContextDescriptor<
1086+
ObjCInteropKind, PointerSize>>(contextDescriptor)) {
1087+
auto anonymousDescriptorName = readAnonymousNameFromAnonymousDescriptor(
1088+
anonymousDescriptor, contextDescriptorAddress);
1089+
if (!anonymousDescriptorName.hasValue())
1090+
return llvm::None;
1091+
else
1092+
return ContextNameInfo{anonymousDescriptorName.getValue(),
1093+
contextDescriptorAddress, true};
1094+
} else {
1095+
Error = "Unexpected type of context descriptor.";
1096+
return llvm::None;
1097+
}
1098+
}
1099+
1100+
void getParentContextChain(
1101+
uintptr_t contextDescriptorAddress,
1102+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1103+
*contextDescriptor,
1104+
std::vector<ContextNameInfo> &chain) {
1105+
const auto parentDescriptorAddress = getParentDescriptorAddress(
1106+
contextDescriptorAddress, contextDescriptor);
1107+
1108+
auto addParentNameAndRecurse =
1109+
[&](uintptr_t parentContextDescriptorAddress,
1110+
std::vector<ContextNameInfo> &chain) -> void {
10621111
auto parentContextDescriptorBytes = OpaqueByteReader(
1063-
remote::RemoteAddress(descriptorAddress),
1112+
remote::RemoteAddress(parentContextDescriptorAddress),
10641113
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
10651114
if (!parentContextDescriptorBytes.get()) {
10661115
Error = "Failed to read context descriptor.";
1067-
return llvm::None;
1116+
return;
10681117
}
1069-
const ExternalContextDescriptor<ObjCInteropKind,
1070-
PointerSize> *parentContextDescriptor =
1118+
const auto parentDescriptor =
10711119
(const ExternalContextDescriptor<ObjCInteropKind, PointerSize> *)
10721120
parentContextDescriptorBytes.get();
1073-
1074-
if (auto moduleDescriptor = dyn_cast<
1075-
ExternalModuleContextDescriptor<ObjCInteropKind, PointerSize>>(
1076-
parentContextDescriptor)) {
1077-
auto moduleDescriptorName = readModuleNameFromModuleDescriptor(
1078-
moduleDescriptor, parentTargetAddress);
1079-
if (!moduleDescriptorName.hasValue())
1080-
return llvm::None;
1081-
else
1082-
optionalParentName = moduleDescriptorName;
1083-
} else if (auto typeDescriptor =
1084-
dyn_cast<ExternalTypeContextDescriptor<ObjCInteropKind,
1085-
PointerSize>>(
1086-
parentContextDescriptor)) {
1087-
auto typeDescriptorName = readTypeNameFromTypeDescriptor(
1088-
typeDescriptor, parentTargetAddress);
1089-
if (!typeDescriptorName.hasValue())
1090-
return llvm::None;
1091-
else
1092-
optionalParentName = typeDescriptorName;
1093-
// Recurse to get this type's parent.
1094-
auto optionalParentParentName =
1095-
getParentContextName(descriptorAddress);
1096-
if (optionalParentParentName.hasValue()) {
1097-
optionalParentName = optionalParentParentName.getValue() + "." +
1098-
optionalParentName.getValue();
1099-
}
1100-
} else {
1101-
Error = "Unexpected type of parent context descriptor.";
1102-
return llvm::None;
1121+
const auto parentNameInfo =
1122+
getContextName(parentContextDescriptorAddress, parentDescriptor);
1123+
if (!parentNameInfo.hasValue()) {
1124+
return;
1125+
}
1126+
chain.push_back(parentNameInfo.getValue());
1127+
if (!isModuleDescriptor(parentDescriptor)) {
1128+
getParentContextChain(parentContextDescriptorAddress,
1129+
parentDescriptor, chain);
11031130
}
1104-
1105-
return optionalParentName;
11061131
};
11071132

1108-
// Set low bit indicates that this is an indirect
1109-
// reference
1110-
if (parentTargetAddress & 0x1) {
1111-
auto adjustedParentTargetAddress = parentTargetAddress & ~0x1;
1133+
// Set low bit indicates that this is an indirect reference
1134+
if (parentDescriptorAddress & 0x1) {
1135+
auto adjustedParentTargetAddress = parentDescriptorAddress & ~0x1;
11121136
if (auto symbol = OpaquePointerReader(
11131137
remote::RemoteAddress(adjustedParentTargetAddress),
11141138
PointerSize)) {
@@ -1117,20 +1141,21 @@ class TypeRefBuilder {
11171141
auto demangledRoot =
11181142
Ctx.demangleSymbolAsNode(symbol->getSymbol().str());
11191143
assert(demangledRoot->getKind() == Node::Kind::Global);
1120-
optionalParentContextName =
1144+
std::string nodeName =
11211145
nodeToString(demangledRoot->getChild(0)->getChild(0));
1146+
chain.push_back(
1147+
ContextNameInfo{nodeName, adjustedParentTargetAddress, false});
11221148
} else {
1123-
optionalParentContextName =
1124-
readContextParentName(adjustedParentTargetAddress);
1149+
addParentNameAndRecurse(adjustedParentTargetAddress, chain);
11251150
}
11261151
} else {
11271152
Error = "Error reading external symbol address.";
1128-
return llvm::None;
1153+
return;
11291154
}
11301155
} else {
1131-
optionalParentContextName = readContextParentName(parentTargetAddress);
1156+
addParentNameAndRecurse(parentDescriptorAddress, chain);
11321157
}
1133-
return optionalParentContextName;
1158+
return;
11341159
}
11351160

11361161
llvm::Optional<std::string> readTypeNameFromTypeDescriptor(
@@ -1175,6 +1200,70 @@ class TypeRefBuilder {
11751200
return parentName;
11761201
}
11771202

1203+
llvm::Optional<std::string> readAnonymousNameFromAnonymousDescriptor(
1204+
const ExternalAnonymousContextDescriptor<ObjCInteropKind, PointerSize>
1205+
*anonymousDescriptor,
1206+
uintptr_t anonymousDescriptorAddress) {
1207+
if (!anonymousDescriptor->hasMangledName()) {
1208+
std::stringstream stream;
1209+
stream << "(unknown context at $" << std::hex
1210+
<< anonymousDescriptorAddress << ")";
1211+
return stream.str();
1212+
}
1213+
return llvm::None;
1214+
}
1215+
1216+
std::string constructFullyQualifiedNameFromContextChain(
1217+
const std::vector<ContextNameInfo> &contextNameChain) {
1218+
std::string newQualifiedTypeName = "";
1219+
std::vector<std::string> reversedQualifiedTypeNameMembers;
1220+
1221+
// Traverse the context chain, adding up context names.
1222+
// Anonymous contexts require special handling: when a type is nested in
1223+
// an anonymous context, its qualified name is printed as `(type_name in
1224+
// $hex_val)` where hex_val is the address of the descriptor of the
1225+
// anonymous parent context.
1226+
bool skipNext = false;
1227+
for (size_t i = 0; i < contextNameChain.size(); ++i) {
1228+
if (skipNext) {
1229+
skipNext = false;
1230+
continue;
1231+
}
1232+
const auto &contextNameInfo = contextNameChain[i];
1233+
bool lastContext = (i == contextNameChain.size() - 1);
1234+
bool currentContextIsAnonymous = contextNameInfo.isAnonymous;
1235+
bool nextContextIsAnonymous =
1236+
lastContext ? false : contextNameChain[i + 1].isAnonymous;
1237+
if (nextContextIsAnonymous && !currentContextIsAnonymous) {
1238+
std::stringstream stream;
1239+
stream << "(" << contextNameInfo.name << " in $" << std::hex
1240+
<< contextNameChain[i + 1].descriptorAddress << ")";
1241+
reversedQualifiedTypeNameMembers.push_back(stream.str());
1242+
skipNext = true;
1243+
} else if (nextContextIsAnonymous && currentContextIsAnonymous) {
1244+
1245+
} else if (!nextContextIsAnonymous && !currentContextIsAnonymous) {
1246+
reversedQualifiedTypeNameMembers.push_back(contextNameInfo.name);
1247+
} else if (!nextContextIsAnonymous && currentContextIsAnonymous) {
1248+
reversedQualifiedTypeNameMembers.push_back(contextNameInfo.name);
1249+
} else {
1250+
llvm_unreachable("Exhausted possibilities.");
1251+
}
1252+
}
1253+
1254+
// Combine the individual context name reps into a single fully-qualified
1255+
// name string
1256+
for (auto it = reversedQualifiedTypeNameMembers.rbegin();
1257+
it != reversedQualifiedTypeNameMembers.rend(); ++it) {
1258+
newQualifiedTypeName.append(*it);
1259+
if (std::next(it) != reversedQualifiedTypeNameMembers.rend()) {
1260+
newQualifiedTypeName.append(".");
1261+
}
1262+
}
1263+
1264+
return newQualifiedTypeName;
1265+
}
1266+
11781267
llvm::Optional<std::string> readProtocolNameFromProtocolDescriptor(
11791268
uintptr_t protocolDescriptorAddress) {
11801269
std::string protocolName;
@@ -1297,14 +1386,14 @@ class TypeRefBuilder {
12971386
else
12981387
typeName = optionalTypeName.getValue();
12991388

1300-
// Prepend the parent context name
1301-
auto optionalParentName =
1302-
getParentContextName(contextTypeDescriptorAddress);
1303-
if (optionalParentName.hasValue()) {
1304-
typeName = optionalParentName.getValue() + "." + typeName;
1305-
}
1306-
1307-
return std::make_pair(mangledTypeName, typeName);
1389+
std::vector<ContextNameInfo> contextNameChain;
1390+
contextNameChain.push_back(
1391+
ContextNameInfo{typeName, contextTypeDescriptorAddress, false});
1392+
getParentContextChain(contextTypeDescriptorAddress, contextDescriptor,
1393+
contextNameChain);
1394+
std::string fullyQualifiedName =
1395+
constructFullyQualifiedNameFromContextChain(contextNameChain);
1396+
return std::make_pair(mangledTypeName, fullyQualifiedName);
13081397
}
13091398

13101399
/// Extract protocol name from a Conformance Descriptor
@@ -1332,6 +1421,33 @@ class TypeRefBuilder {
13321421
(const char *)protocolDescriptorFieldAddress,
13331422
(int32_t)*protocolDescriptorOffset);
13341423

1424+
auto constructFullyQualifiedProtocolName =
1425+
[&](uintptr_t protocolDescriptorAddress)
1426+
-> llvm::Optional<std::string> {
1427+
auto protocolName =
1428+
readProtocolNameFromProtocolDescriptor(protocolDescriptorAddress);
1429+
1430+
// Read the protocol conformance descriptor itself
1431+
auto protocolContextDescriptorBytes = OpaqueByteReader(
1432+
remote::RemoteAddress(protocolDescriptorAddress),
1433+
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
1434+
if (!protocolContextDescriptorBytes.get()) {
1435+
Error = "Failed to read context (protocol) descriptor.";
1436+
return llvm::None;
1437+
}
1438+
const ExternalContextDescriptor<ObjCInteropKind,
1439+
PointerSize> *protocolDescriptor =
1440+
(const ExternalContextDescriptor<ObjCInteropKind, PointerSize> *)
1441+
protocolContextDescriptorBytes.get();
1442+
1443+
std::vector<ContextNameInfo> contextNameChain;
1444+
contextNameChain.push_back(ContextNameInfo{
1445+
protocolName.getValue(), protocolDescriptorAddress, false});
1446+
getParentContextChain(protocolDescriptorAddress, protocolDescriptor,
1447+
contextNameChain);
1448+
return constructFullyQualifiedNameFromContextChain(contextNameChain);
1449+
};
1450+
13351451
// Set low bit indicates that this is an indirect
13361452
// reference
13371453
if (protocolDescriptorTarget & 0x1) {
@@ -1350,16 +1466,9 @@ class TypeRefBuilder {
13501466
nodeToString(demangledRoot->getChild(0)->getChild(0));
13511467
} else {
13521468
// This is an absolute address of a protocol descriptor
1353-
auto protocolDescriptorAddress = symbol->getOffset();
1354-
protocolName = readProtocolNameFromProtocolDescriptor(
1355-
protocolDescriptorAddress);
1356-
// Prepend the parent context name
1357-
auto optionalParentName =
1358-
getParentContextName(protocolDescriptorAddress);
1359-
if (optionalParentName.hasValue()) {
1360-
protocolName =
1361-
optionalParentName.getValue() + "." + *protocolName;
1362-
}
1469+
auto protocolDescriptorAddress = (uintptr_t)symbol->getOffset();
1470+
protocolName =
1471+
constructFullyQualifiedProtocolName(protocolDescriptorAddress);
13631472
}
13641473
} else {
13651474
Error = "Error reading external protocol address.";
@@ -1369,13 +1478,7 @@ class TypeRefBuilder {
13691478
// If this is a direct reference, get symbol name from the protocol
13701479
// descriptor.
13711480
protocolName =
1372-
readProtocolNameFromProtocolDescriptor(protocolDescriptorTarget);
1373-
// Prepend the parent context name
1374-
auto optionalParentName =
1375-
getParentContextName(protocolDescriptorTarget);
1376-
if (optionalParentName.hasValue()) {
1377-
protocolName = optionalParentName.getValue() + "." + *protocolName;
1378-
}
1481+
constructFullyQualifiedProtocolName(protocolDescriptorTarget);
13791482
}
13801483

13811484
return protocolName;

test/Reflection/Inputs/Conformances.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ struct StructA : MyProto, Hashable {
33
var x: Int
44
}
55

6+
struct SomeStruct {
7+
public func someFunc() -> Int {
8+
struct SomeNestedStruct : MyProto {}
9+
return 42
10+
}
11+
}
12+
613
struct foo {
714
struct bar {
815
struct baz {

0 commit comments

Comments
 (0)