Skip to content

Commit ee312bc

Browse files
authored
Merge pull request #42190 from artemcm/AnonymousContextFullyQualifiedTypeNameReconstruction
[Static Mirror] Handle anonymous contexts when re-constructing fully-qualified type names
2 parents 0b09d6b + bc79518 commit ee312bc

File tree

4 files changed

+210
-96
lines changed

4 files changed

+210
-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

@@ -1035,88 +1036,111 @@ class TypeRefBuilder {
10351036
OpaquePointerReader(pointerReader),
10361037
OpaqueDynamicSymbolResolver(dynamicSymbolResolver) {}
10371038

1038-
llvm::Optional<std::string>
1039-
getParentContextName(uintptr_t contextDescriptorAddress) {
1040-
llvm::Optional<std::string> optionalParentContextName;
1041-
auto contextTypeDescriptorBytes = OpaqueByteReader(
1042-
remote::RemoteAddress(contextDescriptorAddress),
1043-
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
1044-
if (!contextTypeDescriptorBytes.get()) {
1045-
Error = "Failed to read context descriptor.";
1046-
return llvm::None;
1047-
}
1048-
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1049-
*contextDescriptor =
1050-
(const ExternalContextDescriptor<ObjCInteropKind, PointerSize> *)
1051-
contextTypeDescriptorBytes.get();
1039+
struct ContextNameInfo {
1040+
std::string name;
1041+
uintptr_t descriptorAddress;
1042+
bool isAnonymous;
1043+
1044+
~ContextNameInfo() {}
1045+
};
1046+
1047+
bool isModuleDescriptor(
1048+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1049+
*contextDescriptor) {
1050+
return isa<ExternalModuleContextDescriptor<ObjCInteropKind, PointerSize>>(
1051+
contextDescriptor);
1052+
}
10521053

1054+
uintptr_t getParentDescriptorAddress(
1055+
uintptr_t contextDescriptorAddress,
1056+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1057+
*contextDescriptor) {
10531058
auto parentOffsetAddress = detail::applyRelativeOffset(
10541059
(const char *)contextDescriptorAddress,
10551060
(int32_t)contextDescriptor->getParentOffset());
1056-
auto parentOffsetBytes = OpaqueByteReader(
1061+
auto parentOfsetBytes = OpaqueByteReader(
10571062
remote::RemoteAddress(parentOffsetAddress), sizeof(uint32_t));
1058-
if (!parentOffsetBytes.get()) {
1059-
Error = "Failed to parent offset in a type descriptor.";
1060-
return llvm::None;
1061-
}
1062-
auto parentFieldOffset = (const int32_t *)parentOffsetBytes.get();
1063+
auto parentFieldOffset = (const int32_t *)parentOfsetBytes.get();
10631064
auto parentTargetAddress = detail::applyRelativeOffset(
10641065
(const char *)parentOffsetAddress, *parentFieldOffset);
1066+
return parentTargetAddress;
1067+
}
10651068

1066-
//
1067-
auto readContextParentName =
1068-
[&](uintptr_t descriptorAddress) -> llvm::Optional<std::string> {
1069-
llvm::Optional<std::string> optionalParentName;
1069+
llvm::Optional<ContextNameInfo>
1070+
getContextName(uintptr_t contextDescriptorAddress,
1071+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1072+
*contextDescriptor) {
1073+
if (auto moduleDescriptor = dyn_cast<
1074+
ExternalModuleContextDescriptor<ObjCInteropKind, PointerSize>>(
1075+
contextDescriptor)) {
1076+
auto moduleDescriptorName = readModuleNameFromModuleDescriptor(
1077+
moduleDescriptor, contextDescriptorAddress);
1078+
if (!moduleDescriptorName.hasValue())
1079+
return llvm::None;
1080+
else
1081+
return ContextNameInfo{moduleDescriptorName.getValue(),
1082+
contextDescriptorAddress, false};
1083+
} else if (auto typeDescriptor = dyn_cast<ExternalTypeContextDescriptor<
1084+
ObjCInteropKind, PointerSize>>(contextDescriptor)) {
1085+
auto typeDescriptorName = readTypeNameFromTypeDescriptor(
1086+
typeDescriptor, contextDescriptorAddress);
1087+
if (!typeDescriptorName.hasValue())
1088+
return llvm::None;
1089+
else
1090+
return ContextNameInfo{typeDescriptorName.getValue(),
1091+
contextDescriptorAddress, false};
1092+
} else if (auto anonymousDescriptor =
1093+
dyn_cast<ExternalAnonymousContextDescriptor<
1094+
ObjCInteropKind, PointerSize>>(contextDescriptor)) {
1095+
auto anonymousDescriptorName = readAnonymousNameFromAnonymousDescriptor(
1096+
anonymousDescriptor, contextDescriptorAddress);
1097+
if (!anonymousDescriptorName.hasValue())
1098+
return llvm::None;
1099+
else
1100+
return ContextNameInfo{anonymousDescriptorName.getValue(),
1101+
contextDescriptorAddress, true};
1102+
} else {
1103+
Error = "Unexpected type of context descriptor.";
1104+
return llvm::None;
1105+
}
1106+
}
1107+
1108+
void getParentContextChain(
1109+
uintptr_t contextDescriptorAddress,
1110+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1111+
*contextDescriptor,
1112+
std::vector<ContextNameInfo> &chain) {
1113+
const auto parentDescriptorAddress = getParentDescriptorAddress(
1114+
contextDescriptorAddress, contextDescriptor);
1115+
1116+
auto addParentNameAndRecurse =
1117+
[&](uintptr_t parentContextDescriptorAddress,
1118+
std::vector<ContextNameInfo> &chain) -> void {
10701119
auto parentContextDescriptorBytes = OpaqueByteReader(
1071-
remote::RemoteAddress(descriptorAddress),
1120+
remote::RemoteAddress(parentContextDescriptorAddress),
10721121
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
10731122
if (!parentContextDescriptorBytes.get()) {
10741123
Error = "Failed to read context descriptor.";
1075-
return llvm::None;
1124+
return;
10761125
}
1077-
const ExternalContextDescriptor<ObjCInteropKind,
1078-
PointerSize> *parentContextDescriptor =
1126+
const auto parentDescriptor =
10791127
(const ExternalContextDescriptor<ObjCInteropKind, PointerSize> *)
10801128
parentContextDescriptorBytes.get();
1081-
1082-
if (auto moduleDescriptor = dyn_cast<
1083-
ExternalModuleContextDescriptor<ObjCInteropKind, PointerSize>>(
1084-
parentContextDescriptor)) {
1085-
auto moduleDescriptorName = readModuleNameFromModuleDescriptor(
1086-
moduleDescriptor, parentTargetAddress);
1087-
if (!moduleDescriptorName.hasValue())
1088-
return llvm::None;
1089-
else
1090-
optionalParentName = moduleDescriptorName;
1091-
} else if (auto typeDescriptor =
1092-
dyn_cast<ExternalTypeContextDescriptor<ObjCInteropKind,
1093-
PointerSize>>(
1094-
parentContextDescriptor)) {
1095-
auto typeDescriptorName = readTypeNameFromTypeDescriptor(
1096-
typeDescriptor, parentTargetAddress);
1097-
if (!typeDescriptorName.hasValue())
1098-
return llvm::None;
1099-
else
1100-
optionalParentName = typeDescriptorName;
1101-
// Recurse to get this type's parent.
1102-
auto optionalParentParentName =
1103-
getParentContextName(descriptorAddress);
1104-
if (optionalParentParentName.hasValue()) {
1105-
optionalParentName = optionalParentParentName.getValue() + "." +
1106-
optionalParentName.getValue();
1107-
}
1108-
} else {
1109-
Error = "Unexpected type of parent context descriptor.";
1110-
return llvm::None;
1129+
const auto parentNameInfo =
1130+
getContextName(parentContextDescriptorAddress, parentDescriptor);
1131+
if (!parentNameInfo.hasValue()) {
1132+
return;
1133+
}
1134+
chain.push_back(parentNameInfo.getValue());
1135+
if (!isModuleDescriptor(parentDescriptor)) {
1136+
getParentContextChain(parentContextDescriptorAddress,
1137+
parentDescriptor, chain);
11111138
}
1112-
1113-
return optionalParentName;
11141139
};
11151140

1116-
// Set low bit indicates that this is an indirect
1117-
// reference
1118-
if (parentTargetAddress & 0x1) {
1119-
auto adjustedParentTargetAddress = parentTargetAddress & ~0x1;
1141+
// Set low bit indicates that this is an indirect reference
1142+
if (parentDescriptorAddress & 0x1) {
1143+
auto adjustedParentTargetAddress = parentDescriptorAddress & ~0x1;
11201144
if (auto symbol = OpaquePointerReader(
11211145
remote::RemoteAddress(adjustedParentTargetAddress),
11221146
PointerSize)) {
@@ -1125,20 +1149,21 @@ class TypeRefBuilder {
11251149
auto demangledRoot =
11261150
Ctx.demangleSymbolAsNode(symbol->getSymbol().str());
11271151
assert(demangledRoot->getKind() == Node::Kind::Global);
1128-
optionalParentContextName =
1152+
std::string nodeName =
11291153
nodeToString(demangledRoot->getChild(0)->getChild(0));
1154+
chain.push_back(
1155+
ContextNameInfo{nodeName, adjustedParentTargetAddress, false});
11301156
} else {
1131-
optionalParentContextName =
1132-
readContextParentName(adjustedParentTargetAddress);
1157+
addParentNameAndRecurse(adjustedParentTargetAddress, chain);
11331158
}
11341159
} else {
11351160
Error = "Error reading external symbol address.";
1136-
return llvm::None;
1161+
return;
11371162
}
11381163
} else {
1139-
optionalParentContextName = readContextParentName(parentTargetAddress);
1164+
addParentNameAndRecurse(parentDescriptorAddress, chain);
11401165
}
1141-
return optionalParentContextName;
1166+
return;
11421167
}
11431168

11441169
llvm::Optional<std::string> readTypeNameFromTypeDescriptor(
@@ -1183,6 +1208,70 @@ class TypeRefBuilder {
11831208
return parentName;
11841209
}
11851210

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

1310-
// Prepend the parent context name
1311-
auto optionalParentName =
1312-
getParentContextName(contextTypeDescriptorAddress);
1313-
if (optionalParentName.hasValue()) {
1314-
typeName = optionalParentName.getValue() + "." + typeName;
1315-
}
1316-
1317-
return std::make_pair(mangledTypeName, typeName);
1399+
std::vector<ContextNameInfo> contextNameChain;
1400+
contextNameChain.push_back(
1401+
ContextNameInfo{typeName, contextTypeDescriptorAddress, false});
1402+
getParentContextChain(contextTypeDescriptorAddress, contextDescriptor,
1403+
contextNameChain);
1404+
std::string fullyQualifiedName =
1405+
constructFullyQualifiedNameFromContextChain(contextNameChain);
1406+
return std::make_pair(mangledTypeName, fullyQualifiedName);
13181407
}
13191408

13201409
/// Extract protocol name from a Conformance Descriptor
@@ -1342,6 +1431,33 @@ class TypeRefBuilder {
13421431
(const char *)protocolDescriptorFieldAddress,
13431432
(int32_t)*protocolDescriptorOffset);
13441433

1434+
auto constructFullyQualifiedProtocolName =
1435+
[&](uintptr_t protocolDescriptorAddress)
1436+
-> llvm::Optional<std::string> {
1437+
auto protocolName =
1438+
readProtocolNameFromProtocolDescriptor(protocolDescriptorAddress);
1439+
1440+
// Read the protocol conformance descriptor itself
1441+
auto protocolContextDescriptorBytes = OpaqueByteReader(
1442+
remote::RemoteAddress(protocolDescriptorAddress),
1443+
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
1444+
if (!protocolContextDescriptorBytes.get()) {
1445+
Error = "Failed to read context (protocol) descriptor.";
1446+
return llvm::None;
1447+
}
1448+
const ExternalContextDescriptor<ObjCInteropKind,
1449+
PointerSize> *protocolDescriptor =
1450+
(const ExternalContextDescriptor<ObjCInteropKind, PointerSize> *)
1451+
protocolContextDescriptorBytes.get();
1452+
1453+
std::vector<ContextNameInfo> contextNameChain;
1454+
contextNameChain.push_back(ContextNameInfo{
1455+
protocolName.getValue(), protocolDescriptorAddress, false});
1456+
getParentContextChain(protocolDescriptorAddress, protocolDescriptor,
1457+
contextNameChain);
1458+
return constructFullyQualifiedNameFromContextChain(contextNameChain);
1459+
};
1460+
13451461
// Set low bit indicates that this is an indirect
13461462
// reference
13471463
if (protocolDescriptorTarget & 0x1) {
@@ -1360,16 +1476,9 @@ class TypeRefBuilder {
13601476
nodeToString(demangledRoot->getChild(0)->getChild(0));
13611477
} else {
13621478
// This is an absolute address of a protocol descriptor
1363-
auto protocolDescriptorAddress = symbol->getOffset();
1364-
protocolName = readProtocolNameFromProtocolDescriptor(
1365-
protocolDescriptorAddress);
1366-
// Prepend the parent context name
1367-
auto optionalParentName =
1368-
getParentContextName(protocolDescriptorAddress);
1369-
if (optionalParentName.hasValue()) {
1370-
protocolName =
1371-
optionalParentName.getValue() + "." + *protocolName;
1372-
}
1479+
auto protocolDescriptorAddress = (uintptr_t)symbol->getOffset();
1480+
protocolName =
1481+
constructFullyQualifiedProtocolName(protocolDescriptorAddress);
13731482
}
13741483
} else {
13751484
Error = "Error reading external protocol address.";
@@ -1379,13 +1488,7 @@ class TypeRefBuilder {
13791488
// If this is a direct reference, get symbol name from the protocol
13801489
// descriptor.
13811490
protocolName =
1382-
readProtocolNameFromProtocolDescriptor(protocolDescriptorTarget);
1383-
// Prepend the parent context name
1384-
auto optionalParentName =
1385-
getParentContextName(protocolDescriptorTarget);
1386-
if (optionalParentName.hasValue()) {
1387-
protocolName = optionalParentName.getValue() + "." + *protocolName;
1388-
}
1491+
constructFullyQualifiedProtocolName(protocolDescriptorTarget);
13891492
}
13901493

13911494
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)