Skip to content

Commit cb27fe3

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 767f7b7 commit cb27fe3

File tree

4 files changed

+208
-94
lines changed

4 files changed

+208
-94
lines changed

include/swift/ABI/Metadata.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2792,6 +2792,9 @@ struct TargetAnonymousContextDescriptor final
27922792
};
27932793
using AnonymousContextDescriptor = TargetAnonymousContextDescriptor<InProcess>;
27942794

2795+
template<template <typename Runtime> class ObjCInteropKind, unsigned PointerSize>
2796+
using ExternalAnonymousContextDescriptor = TargetAnonymousContextDescriptor<External<ObjCInteropKind<RuntimeTarget<PointerSize>>>>;
2797+
27952798
/// A protocol descriptor.
27962799
///
27972800
/// Protocol descriptors contain information about the contents of a protocol:

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 197 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
#include "swift/Reflection/TypeLowering.h"
2525
#include "swift/Reflection/TypeRef.h"
2626
#include "llvm/ADT/Optional.h"
27+
#include "llvm/Support/Debug.h"
2728
#include <iomanip>
2829
#include <iostream>
2930
#include <ostream>
31+
#include <sstream>
3032
#include <unordered_map>
3133
#include <vector>
3234

@@ -961,88 +963,111 @@ class TypeRefBuilder {
961963
OpaqueStringReader(stringReader), OpaquePointerReader(pointerReader) {
962964
}
963965

964-
llvm::Optional<std::string>
965-
getParentContextName(uintptr_t contextDescriptorAddress) {
966-
llvm::Optional<std::string> optionalParentContextName;
967-
auto contextTypeDescriptorBytes = OpaqueByteReader(
968-
remote::RemoteAddress(contextDescriptorAddress),
969-
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
970-
if (!contextTypeDescriptorBytes.get()) {
971-
Error = "Failed to read context descriptor.";
972-
return llvm::None;
973-
}
974-
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
975-
*contextDescriptor =
976-
(const ExternalContextDescriptor<ObjCInteropKind, PointerSize> *)
977-
contextTypeDescriptorBytes.get();
966+
struct ContextNameInfo {
967+
std::string name;
968+
uintptr_t descriptorAddress;
969+
bool isAnonymous;
970+
971+
~ContextNameInfo() {}
972+
};
973+
974+
bool isModuleDescriptor(
975+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
976+
*contextDescriptor) {
977+
return isa<ExternalModuleContextDescriptor<ObjCInteropKind, PointerSize>>(
978+
contextDescriptor);
979+
}
978980

981+
uintptr_t getParentDescriptorAddress(
982+
uintptr_t contextDescriptorAddress,
983+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
984+
*contextDescriptor) {
979985
auto parentOffsetAddress = detail::applyRelativeOffset(
980986
(const char *)contextDescriptorAddress,
981987
(int32_t)contextDescriptor->getParentOffset());
982988
auto parentOfsetBytes = OpaqueByteReader(
983989
remote::RemoteAddress(parentOffsetAddress), sizeof(uint32_t));
984-
if (!parentOfsetBytes.get()) {
985-
Error = "Failed to parent offset in a type descriptor.";
986-
return llvm::None;
987-
}
988990
auto parentFieldOffset = (const int32_t *)parentOfsetBytes.get();
989991
auto parentTargetAddress = detail::applyRelativeOffset(
990992
(const char *)parentOffsetAddress, *parentFieldOffset);
993+
return parentTargetAddress;
994+
}
995+
996+
llvm::Optional<ContextNameInfo>
997+
getContextName(uintptr_t contextDescriptorAddress,
998+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
999+
*contextDescriptor) {
1000+
if (auto moduleDescriptor = dyn_cast<
1001+
ExternalModuleContextDescriptor<ObjCInteropKind, PointerSize>>(
1002+
contextDescriptor)) {
1003+
auto moduleDescriptorName = readModuleNameFromModuleDescriptor(
1004+
moduleDescriptor, contextDescriptorAddress);
1005+
if (!moduleDescriptorName.hasValue())
1006+
return llvm::None;
1007+
else
1008+
return ContextNameInfo{moduleDescriptorName.getValue(),
1009+
contextDescriptorAddress, false};
1010+
} else if (auto typeDescriptor = dyn_cast<ExternalTypeContextDescriptor<
1011+
ObjCInteropKind, PointerSize>>(contextDescriptor)) {
1012+
auto typeDescriptorName = readTypeNameFromTypeDescriptor(
1013+
typeDescriptor, contextDescriptorAddress);
1014+
if (!typeDescriptorName.hasValue())
1015+
return llvm::None;
1016+
else
1017+
return ContextNameInfo{typeDescriptorName.getValue(),
1018+
contextDescriptorAddress, false};
1019+
} else if (auto anonymousDescriptor =
1020+
dyn_cast<ExternalAnonymousContextDescriptor<
1021+
ObjCInteropKind, PointerSize>>(contextDescriptor)) {
1022+
auto anonymousDescriptorName = readAnonymousNameFromAnonymousDescriptor(
1023+
anonymousDescriptor, contextDescriptorAddress);
1024+
if (!anonymousDescriptorName.hasValue())
1025+
return llvm::None;
1026+
else
1027+
return ContextNameInfo{anonymousDescriptorName.getValue(),
1028+
contextDescriptorAddress, true};
1029+
} else {
1030+
Error = "Unexpected type of context descriptor.";
1031+
return llvm::None;
1032+
}
1033+
}
9911034

992-
//
993-
auto readContextParentName =
994-
[&](uintptr_t descriptorAddress) -> llvm::Optional<std::string> {
995-
llvm::Optional<std::string> optionalParentName;
1035+
void getParentContextChain(
1036+
uintptr_t contextDescriptorAddress,
1037+
const ExternalContextDescriptor<ObjCInteropKind, PointerSize>
1038+
*contextDescriptor,
1039+
std::vector<ContextNameInfo> &chain) {
1040+
const auto parentDescriptorAddress = getParentDescriptorAddress(
1041+
contextDescriptorAddress, contextDescriptor);
1042+
1043+
auto addParentNameAndRecurse =
1044+
[&](uintptr_t parentContextDescriptorAddress,
1045+
std::vector<ContextNameInfo> &chain) -> void {
9961046
auto parentContextDescriptorBytes = OpaqueByteReader(
997-
remote::RemoteAddress(descriptorAddress),
1047+
remote::RemoteAddress(parentContextDescriptorAddress),
9981048
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
9991049
if (!parentContextDescriptorBytes.get()) {
10001050
Error = "Failed to read context descriptor.";
1001-
return llvm::None;
1051+
return;
10021052
}
1003-
const ExternalContextDescriptor<ObjCInteropKind,
1004-
PointerSize> *parentContextDescriptor =
1053+
const auto parentDescriptor =
10051054
(const ExternalContextDescriptor<ObjCInteropKind, PointerSize> *)
10061055
parentContextDescriptorBytes.get();
1007-
1008-
if (auto moduleDescriptor = dyn_cast<
1009-
ExternalModuleContextDescriptor<ObjCInteropKind, PointerSize>>(
1010-
parentContextDescriptor)) {
1011-
auto moduleDescriptorName = readModuleNameFromModuleDescriptor(
1012-
moduleDescriptor, parentTargetAddress);
1013-
if (!moduleDescriptorName.hasValue())
1014-
return llvm::None;
1015-
else
1016-
optionalParentName = moduleDescriptorName;
1017-
} else if (auto typeDescriptor =
1018-
dyn_cast<ExternalTypeContextDescriptor<ObjCInteropKind,
1019-
PointerSize>>(
1020-
parentContextDescriptor)) {
1021-
auto typeDescriptorName = readTypeNameFromTypeDescriptor(
1022-
typeDescriptor, parentTargetAddress);
1023-
if (!typeDescriptorName.hasValue())
1024-
return llvm::None;
1025-
else
1026-
optionalParentName = typeDescriptorName;
1027-
// Recurse to get this type's parent.
1028-
auto optionalParentParentName =
1029-
getParentContextName(descriptorAddress);
1030-
if (optionalParentParentName.hasValue()) {
1031-
optionalParentName = optionalParentParentName.getValue() + "." +
1032-
optionalParentName.getValue();
1033-
}
1034-
} else {
1035-
Error = "Unexpected type of parent context descriptor.";
1036-
return llvm::None;
1056+
const auto parentNameInfo =
1057+
getContextName(parentContextDescriptorAddress, parentDescriptor);
1058+
if (!parentNameInfo.hasValue()) {
1059+
return;
1060+
}
1061+
chain.push_back(parentNameInfo.getValue());
1062+
if (!isModuleDescriptor(parentDescriptor)) {
1063+
getParentContextChain(parentContextDescriptorAddress,
1064+
parentDescriptor, chain);
10371065
}
1038-
1039-
return optionalParentName;
10401066
};
10411067

1042-
// Set low bit indicates that this is an indirect
1043-
// reference
1044-
if (parentTargetAddress & 0x1) {
1045-
auto adjustedParentTargetAddress = parentTargetAddress & ~0x1;
1068+
// Set low bit indicates that this is an indirect reference
1069+
if (parentDescriptorAddress & 0x1) {
1070+
auto adjustedParentTargetAddress = parentDescriptorAddress & ~0x1;
10461071
if (auto symbol = OpaquePointerReader(
10471072
remote::RemoteAddress(adjustedParentTargetAddress),
10481073
PointerSize)) {
@@ -1051,20 +1076,21 @@ class TypeRefBuilder {
10511076
auto demangledRoot =
10521077
Ctx.demangleSymbolAsNode(symbol->getSymbol().str());
10531078
assert(demangledRoot->getKind() == Node::Kind::Global);
1054-
optionalParentContextName =
1079+
std::string nodeName =
10551080
nodeToString(demangledRoot->getChild(0)->getChild(0));
1081+
chain.push_back(
1082+
ContextNameInfo{nodeName, adjustedParentTargetAddress, false});
10561083
} else {
1057-
optionalParentContextName =
1058-
readContextParentName(adjustedParentTargetAddress);
1084+
addParentNameAndRecurse(adjustedParentTargetAddress, chain);
10591085
}
10601086
} else {
10611087
Error = "Error reading external symbol address.";
1062-
return llvm::None;
1088+
return;
10631089
}
10641090
} else {
1065-
optionalParentContextName = readContextParentName(parentTargetAddress);
1091+
addParentNameAndRecurse(parentDescriptorAddress, chain);
10661092
}
1067-
return optionalParentContextName;
1093+
return;
10681094
}
10691095

10701096
llvm::Optional<std::string> readTypeNameFromTypeDescriptor(
@@ -1109,6 +1135,70 @@ class TypeRefBuilder {
11091135
return parentName;
11101136
}
11111137

1138+
llvm::Optional<std::string> readAnonymousNameFromAnonymousDescriptor(
1139+
const ExternalAnonymousContextDescriptor<ObjCInteropKind, PointerSize>
1140+
*anonymousDescriptor,
1141+
uintptr_t anonymousDescriptorAddress) {
1142+
if (!anonymousDescriptor->hasMangledName()) {
1143+
std::stringstream stream;
1144+
stream << "(unknown context at $" << std::hex
1145+
<< anonymousDescriptorAddress << ")";
1146+
return stream.str();
1147+
}
1148+
return llvm::None;
1149+
}
1150+
1151+
std::string constructFullyQualifiedNameFromContextChain(
1152+
const std::vector<ContextNameInfo> &contextNameChain) {
1153+
std::string newQualifiedTypeName = "";
1154+
std::vector<std::string> reversedQualifiedTypeNameMembers;
1155+
1156+
// Traverse the context chain, adding up context names.
1157+
// Anonymous contexts require special handling: when a type is nested in
1158+
// an anonymous context, its qualified name is printed as `(type_name in
1159+
// $hex_val)` where hex_val is the address of the descriptor of the
1160+
// anonymous parent context.
1161+
bool skipNext = false;
1162+
for (size_t i = 0; i < contextNameChain.size(); ++i) {
1163+
if (skipNext) {
1164+
skipNext = false;
1165+
continue;
1166+
}
1167+
const auto &contextNameInfo = contextNameChain[i];
1168+
bool lastContext = (i == contextNameChain.size() - 1);
1169+
bool currentContextIsAnonymous = contextNameInfo.isAnonymous;
1170+
bool nextContextIsAnonymous =
1171+
lastContext ? false : contextNameChain[i + 1].isAnonymous;
1172+
if (nextContextIsAnonymous && !currentContextIsAnonymous) {
1173+
std::stringstream stream;
1174+
stream << "(" << contextNameInfo.name << " in $" << std::hex
1175+
<< contextNameChain[i + 1].descriptorAddress << ")";
1176+
reversedQualifiedTypeNameMembers.push_back(stream.str());
1177+
skipNext = true;
1178+
} else if (nextContextIsAnonymous && currentContextIsAnonymous) {
1179+
1180+
} else if (!nextContextIsAnonymous && !currentContextIsAnonymous) {
1181+
reversedQualifiedTypeNameMembers.push_back(contextNameInfo.name);
1182+
} else if (!nextContextIsAnonymous && currentContextIsAnonymous) {
1183+
reversedQualifiedTypeNameMembers.push_back(contextNameInfo.name);
1184+
} else {
1185+
llvm_unreachable("Exhausted possibilities.");
1186+
}
1187+
}
1188+
1189+
// Combine the individual context name reps into a single fully-qualified
1190+
// name string
1191+
for (auto it = reversedQualifiedTypeNameMembers.rbegin();
1192+
it != reversedQualifiedTypeNameMembers.rend(); ++it) {
1193+
newQualifiedTypeName.append(*it);
1194+
if (std::next(it) != reversedQualifiedTypeNameMembers.rend()) {
1195+
newQualifiedTypeName.append(".");
1196+
}
1197+
}
1198+
1199+
return newQualifiedTypeName;
1200+
}
1201+
11121202
llvm::Optional<std::string> readProtocolNameFromProtocolDescriptor(
11131203
uintptr_t protocolDescriptorAddress) {
11141204
std::string protocolName;
@@ -1206,14 +1296,14 @@ class TypeRefBuilder {
12061296
else
12071297
typeName = optionalTypeName.getValue();
12081298

1209-
// Prepend the parent context name
1210-
auto optionalParentName =
1211-
getParentContextName(contextTypeDescriptorAddress);
1212-
if (optionalParentName.hasValue()) {
1213-
typeName = optionalParentName.getValue() + "." + typeName;
1214-
}
1215-
1216-
return typeName;
1299+
std::vector<ContextNameInfo> contextNameChain;
1300+
contextNameChain.push_back(
1301+
ContextNameInfo{typeName, contextTypeDescriptorAddress, false});
1302+
getParentContextChain(contextTypeDescriptorAddress, contextDescriptor,
1303+
contextNameChain);
1304+
std::string fullyQualifiedName =
1305+
constructFullyQualifiedNameFromContextChain(contextNameChain);
1306+
return fullyQualifiedName;
12171307
}
12181308

12191309
/// Extract protocol name from a Conformance Descriptor
@@ -1241,6 +1331,33 @@ class TypeRefBuilder {
12411331
(const char *)protocolDescriptorFieldAddress,
12421332
(int32_t)*protocolDescriptorOffset);
12431333

1334+
auto constructFullyQualifiedProtocolName =
1335+
[&](uintptr_t protocolDescriptorAddress)
1336+
-> llvm::Optional<std::string> {
1337+
auto protocolName =
1338+
readProtocolNameFromProtocolDescriptor(protocolDescriptorAddress);
1339+
1340+
// Read the protocol conformance descriptor itself
1341+
auto protocolContextDescriptorBytes = OpaqueByteReader(
1342+
remote::RemoteAddress(protocolDescriptorAddress),
1343+
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
1344+
if (!protocolContextDescriptorBytes.get()) {
1345+
Error = "Failed to read context (protocol) descriptor.";
1346+
return llvm::None;
1347+
}
1348+
const ExternalContextDescriptor<ObjCInteropKind,
1349+
PointerSize> *protocolDescriptor =
1350+
(const ExternalContextDescriptor<ObjCInteropKind, PointerSize> *)
1351+
protocolContextDescriptorBytes.get();
1352+
1353+
std::vector<ContextNameInfo> contextNameChain;
1354+
contextNameChain.push_back(ContextNameInfo{
1355+
protocolName.getValue(), protocolDescriptorAddress, false});
1356+
getParentContextChain(protocolDescriptorAddress, protocolDescriptor,
1357+
contextNameChain);
1358+
return constructFullyQualifiedNameFromContextChain(contextNameChain);
1359+
};
1360+
12441361
// Set low bit indicates that this is an indirect
12451362
// reference
12461363
if (protocolDescriptorTarget & 0x1) {
@@ -1259,16 +1376,9 @@ class TypeRefBuilder {
12591376
nodeToString(demangledRoot->getChild(0)->getChild(0));
12601377
} else {
12611378
// This is an absolute address of a protocol descriptor
1262-
auto protocolDescriptorAddress = symbol->getOffset();
1263-
protocolName = readProtocolNameFromProtocolDescriptor(
1264-
protocolDescriptorAddress);
1265-
// Prepend the parent context name
1266-
auto optionalParentName =
1267-
getParentContextName(protocolDescriptorAddress);
1268-
if (optionalParentName.hasValue()) {
1269-
protocolName =
1270-
optionalParentName.getValue() + "." + *protocolName;
1271-
}
1379+
auto protocolDescriptorAddress = (uintptr_t)symbol->getOffset();
1380+
protocolName =
1381+
constructFullyQualifiedProtocolName(protocolDescriptorAddress);
12721382
}
12731383
} else {
12741384
Error = "Error reading external protocol address.";
@@ -1278,13 +1388,7 @@ class TypeRefBuilder {
12781388
// If this is a direct reference, get symbol name from the protocol
12791389
// descriptor.
12801390
protocolName =
1281-
readProtocolNameFromProtocolDescriptor(protocolDescriptorTarget);
1282-
// Prepend the parent context name
1283-
auto optionalParentName =
1284-
getParentContextName(protocolDescriptorTarget);
1285-
if (optionalParentName.hasValue()) {
1286-
protocolName = optionalParentName.getValue() + "." + *protocolName;
1287-
}
1391+
constructFullyQualifiedProtocolName(protocolDescriptorTarget);
12881392
}
12891393

12901394
return protocolName;

0 commit comments

Comments
 (0)