Skip to content

Commit b127aac

Browse files
Merge pull request #24781 from aschwaighofer/fix_some_type_dynamic_replacement
Fix dynamic replacement of some type when used with associated types
2 parents 06305b2 + b82d2f2 commit b127aac

15 files changed

+295
-17
lines changed

lib/IRGen/GenDecl.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,25 @@ static std::string getDynamicReplacementSection(IRGenModule &IGM) {
13161316
return sectionName;
13171317
}
13181318

1319+
static std::string getDynamicReplacementSomeSection(IRGenModule &IGM) {
1320+
std::string sectionName;
1321+
switch (IGM.TargetInfo.OutputObjectFormat) {
1322+
case llvm::Triple::UnknownObjectFormat:
1323+
llvm_unreachable("Don't know how to emit field records table for "
1324+
"the selected object format.");
1325+
case llvm::Triple::MachO:
1326+
sectionName = "__TEXT, __swift5_replac2, regular, no_dead_strip";
1327+
break;
1328+
case llvm::Triple::ELF:
1329+
case llvm::Triple::Wasm:
1330+
sectionName = "swift5_replac2";
1331+
break;
1332+
case llvm::Triple::COFF:
1333+
sectionName = ".sw5reps$B";
1334+
break;
1335+
}
1336+
return sectionName;
1337+
}
13191338
llvm::GlobalVariable *IRGenModule::getGlobalForDynamicallyReplaceableThunk(
13201339
LinkEntity &entity, llvm::Type *type, ForDefinition_t forDefinition) {
13211340
return cast<llvm::GlobalVariable>(
@@ -1469,6 +1488,41 @@ void IRGenerator::emitDynamicReplacements() {
14691488
/*isConstant*/ true, llvm::GlobalValue::PrivateLinkage);
14701489
autoReplVar->setSection(getDynamicReplacementSection(IGM));
14711490
IGM.addUsedGlobal(autoReplVar);
1491+
1492+
if (origFuncTypes.empty())
1493+
return;
1494+
// Emit records for replacing opaque type descriptor for some types.
1495+
// struct AutomaticReplacementsSome {
1496+
// uint32t flags; // unused
1497+
// uint32t numReplacements;
1498+
// struct Entry {
1499+
// RelativeIndirectablePointer<OpaqueTypeDescriptor*> orig;
1500+
// RelativeDirectPointer<OpaqueTypeDescriptor*> replacement;
1501+
// uint32_t flags; // unused.
1502+
// }[numEntries]
1503+
// };
1504+
auto autoReplacementsSome = builder.beginStruct();
1505+
autoReplacementsSome.addInt32(0); // unused flags.
1506+
autoReplacementsSome.addInt32(
1507+
origFuncTypes.size()); // number of replacement entries.
1508+
auto someReplacementsArray = autoReplacementsSome.beginArray();
1509+
for (auto i : indices(origFuncTypes)) {
1510+
auto origDesc =
1511+
LinkEntity::forOpaqueTypeDescriptor(origFuncTypes[i]->getDecl());
1512+
auto replDesc =
1513+
LinkEntity::forOpaqueTypeDescriptor(newFuncTypes[i]->getDecl());
1514+
auto replacement = someReplacementsArray.beginStruct();
1515+
replacement.addRelativeAddress(
1516+
IGM.getAddrOfLLVMVariableOrGOTEquivalent(origDesc));
1517+
replacement.addRelativeAddress(
1518+
IGM.getAddrOfLLVMVariableOrGOTEquivalent(replDesc));
1519+
replacement.finishAndAddTo(someReplacementsArray);
1520+
}
1521+
someReplacementsArray.finishAndAddTo(autoReplacementsSome);
1522+
auto autoReplVar2 = autoReplacementsSome.finishAndCreateGlobal(
1523+
"\x01l_auto_dynamic_replacements_some", IGM.getPointerAlignment(),
1524+
/*isConstant*/ true, llvm::GlobalValue::PrivateLinkage);
1525+
autoReplVar2->setSection(getDynamicReplacementSomeSection(IGM));
14721526
}
14731527

14741528
void IRGenerator::emitEagerClassInitialization() {

stdlib/public/runtime/ImageInspection.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ void addImageProtocolConformanceBlockCallback(const void *start,
8080
uintptr_t size);
8181
void addImageTypeMetadataRecordBlockCallback(const void *start,
8282
uintptr_t size);
83-
void addImageDynamicReplacementBlockCallback(const void *start, uintptr_t size);
83+
void addImageDynamicReplacementBlockCallback(const void *start, uintptr_t size,
84+
const void *start2,
85+
uintptr_t size2);
8486

8587
int lookupSymbol(const void *address, SymbolInfo *info);
8688
void *lookupSection(const char *segment, const char *section, size_t *outSize);

stdlib/public/runtime/ImageInspectionCOFF.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,14 @@ void swift_addNewDSOImage(const void *addr) {
118118
const auto &dynamic_replacements = sections->swift5_repl;
119119
const auto *replacements =
120120
reinterpret_cast<void *>(dynamic_replacements.start);
121-
if (dynamic_replacements.length)
122-
addImageDynamicReplacementBlockCallback(replacements, dynamic_replacements.length);
123-
121+
if (dynamic_replacements.length) {
122+
const auto &dynamic_replacements_some = sections->swift5_reps;
123+
const auto *replacements_some =
124+
reinterpret_cast<void *>(dynamic_replacements_some.start);
125+
addImageDynamicReplacementBlockCallback(
126+
replacements, dynamic_replacements.length, replacements_some,
127+
dynamic_replacements_some.length);
128+
}
124129
}
125130

126131
int swift::lookupSymbol(const void *address, SymbolInfo *info) {

stdlib/public/runtime/ImageInspectionCOFF.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct MetadataSections {
5353
Range swift5_fieldmd;
5454
Range swift5_assocty;
5555
Range swift5_repl;
56+
Range swift5_reps;
5657
};
5758
} // namespace swift
5859

stdlib/public/runtime/ImageInspectionELF.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,14 @@ void swift_addNewDSOImage(const void *addr) {
121121
const auto &dynamic_replacements = sections->swift5_replace;
122122
const auto *replacements =
123123
reinterpret_cast<void *>(dynamic_replacements.start);
124-
if (dynamic_replacements.length)
125-
addImageDynamicReplacementBlockCallback(replacements,
126-
dynamic_replacements.length);
124+
if (dynamic_replacements.length) {
125+
const auto &dynamic_replacements_some = sections->swift5_replac2;
126+
const auto *replacements_some =
127+
reinterpret_cast<void *>(dynamic_replacements_some.start);
128+
addImageDynamicReplacementBlockCallback(
129+
replacements, dynamic_replacements.length, replacements_some,
130+
dynamic_replacements_some.length);
131+
}
127132
}
128133

129134
int swift::lookupSymbol(const void *address, SymbolInfo *info) {

stdlib/public/runtime/ImageInspectionELF.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct MetadataSections {
5353
Range swift5_fieldmd;
5454
Range swift5_assocty;
5555
Range swift5_replace;
56+
Range swift5_replac2;
5657
};
5758
} // namespace swift
5859

stdlib/public/runtime/ImageInspectionMachO.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ constexpr const char TypeMetadataRecordSection[] = "__swift5_types";
4141
/// The Mach-O section name for the section containing dynamic replacements.
4242
/// This lives within SEG_TEXT.
4343
constexpr const char DynamicReplacementSection[] = "__swift5_replace";
44+
constexpr const char DynamicReplacementSomeSection[] = "__swift5_replac2";
4445

4546
constexpr const char TextSegment[] = SEG_TEXT;
4647

@@ -72,6 +73,36 @@ void addImageCallback(const mach_header *mh, intptr_t vmaddr_slide) {
7273
CONSUME_BLOCK(section, size);
7374
}
7475

76+
template <const char *SEGMENT_NAME, const char *SECTION_NAME,
77+
const char *SEGMENT_NAME2, const char *SECTION_NAME2,
78+
void CONSUME_BLOCK(const void *start, uintptr_t size,
79+
const void *start2, uintptr_t size2)>
80+
void addImageCallback2Sections(const mach_header *mh, intptr_t vmaddr_slide) {
81+
#if __POINTER_WIDTH__ == 64
82+
assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!");
83+
#endif
84+
85+
// Look for a section.
86+
unsigned long size;
87+
const uint8_t *section =
88+
getsectiondata(reinterpret_cast<const mach_header_platform *>(mh),
89+
SEGMENT_NAME, SECTION_NAME,
90+
&size);
91+
92+
if (!section)
93+
return;
94+
95+
// Look for another section.
96+
unsigned long size2;
97+
const uint8_t *section2 =
98+
getsectiondata(reinterpret_cast<const mach_header_platform *>(mh),
99+
SEGMENT_NAME2, SECTION_NAME2,
100+
&size2);
101+
if (!section2)
102+
size2 = 0;
103+
104+
CONSUME_BLOCK(section, size, section2, size2);
105+
}
75106
} // end anonymous namespace
76107

77108
void swift::initializeProtocolLookup() {
@@ -93,8 +124,9 @@ void swift::initializeTypeMetadataRecordLookup() {
93124

94125
void swift::initializeDynamicReplacementLookup() {
95126
_dyld_register_func_for_add_image(
96-
addImageCallback<TextSegment, DynamicReplacementSection,
97-
addImageDynamicReplacementBlockCallback>);
127+
addImageCallback2Sections<TextSegment, DynamicReplacementSection,
128+
TextSegment, DynamicReplacementSomeSection,
129+
addImageDynamicReplacementBlockCallback>);
98130
}
99131

100132
int swift::lookupSymbol(const void *address, SymbolInfo *info) {

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,14 +1028,47 @@ Optional<const ProtocolRequirement *> findAssociatedTypeByName(
10281028
swift_runtime_unreachable("associated type names don't line up");
10291029
}
10301030

1031+
namespace {
1032+
static Lazy<Mutex> DynamicReplacementLock;
1033+
}
1034+
1035+
namespace {
1036+
struct OpaqueTypeMappings {
1037+
llvm::DenseMap<const OpaqueTypeDescriptor *, const OpaqueTypeDescriptor *>
1038+
descriptorMapping;
1039+
const OpaqueTypeDescriptor* find(const OpaqueTypeDescriptor *orig) {
1040+
const OpaqueTypeDescriptor *replacement = nullptr;
1041+
DynamicReplacementLock.get().withLock([&] {
1042+
auto entry = descriptorMapping.find(orig);
1043+
if (entry != descriptorMapping.end())
1044+
replacement = entry->second;
1045+
});
1046+
return replacement;
1047+
}
1048+
1049+
// We take a mutex argument to make sure someone is holding the lock.
1050+
void insert(const OpaqueTypeDescriptor *orig,
1051+
const OpaqueTypeDescriptor *replacement, const Mutex &) {
1052+
descriptorMapping[orig] = replacement;
1053+
}
1054+
};
1055+
} // end unnamed namespace
1056+
1057+
static Lazy<OpaqueTypeMappings> opaqueTypeMappings;
1058+
1059+
10311060
static const OpaqueTypeDescriptor *
10321061
_findOpaqueTypeDescriptor(NodePointer demangleNode,
10331062
Demangler &dem) {
10341063
// Directly resolve a symbolic reference.
10351064
if (demangleNode->getKind()
10361065
== Node::Kind::OpaqueTypeDescriptorSymbolicReference) {
10371066
auto context = (const ContextDescriptor *)demangleNode->getIndex();
1038-
return cast<OpaqueTypeDescriptor>(context);
1067+
auto *orig = cast<OpaqueTypeDescriptor>(context);
1068+
if (auto *entry = opaqueTypeMappings.get().find(orig)) {
1069+
return entry;
1070+
}
1071+
return orig;
10391072
}
10401073

10411074
// TODO: Find non-symbolic-referenced opaque decls.
@@ -1976,6 +2009,7 @@ void DynamicReplacementDescriptor::disableReplacement() const {
19762009
}
19772010

19782011
/// An automatic dymamic replacement entry.
2012+
namespace {
19792013
class AutomaticDynamicReplacementEntry {
19802014
RelativeDirectPointer<DynamicReplacementScope, false> replacementScope;
19812015
uint32_t flags;
@@ -2012,16 +2046,64 @@ class AutomaticDynamicReplacements
20122046
}
20132047
};
20142048

2015-
namespace {
2016-
static Lazy<Mutex> DynamicReplacementLock;
2017-
}
2049+
/// A map from original to replaced opaque type descriptor of a some type.
2050+
class DynamicReplacementSomeDescriptor {
2051+
RelativeIndirectablePointer<const OpaqueTypeDescriptor, false>
2052+
originalOpaqueTypeDesc;
2053+
RelativeDirectPointer<const OpaqueTypeDescriptor, false>
2054+
replacementOpaqueTypeDesc;
2055+
2056+
public:
2057+
void enable(const Mutex &lock) const {
2058+
opaqueTypeMappings.get().insert(originalOpaqueTypeDesc.get(),
2059+
replacementOpaqueTypeDesc.get(), lock);
2060+
}
2061+
};
2062+
2063+
/// A list of dynamic replacements of some types.
2064+
class AutomaticDynamicReplacementsSome
2065+
: private swift::ABI::TrailingObjects<AutomaticDynamicReplacementsSome,
2066+
DynamicReplacementSomeDescriptor> {
2067+
uint32_t flags;
2068+
uint32_t numEntries;
2069+
using TrailingObjects =
2070+
swift::ABI::TrailingObjects<AutomaticDynamicReplacementsSome,
2071+
DynamicReplacementSomeDescriptor>;
2072+
friend TrailingObjects;
2073+
2074+
2075+
ArrayRef<DynamicReplacementSomeDescriptor> getReplacementEntries() const {
2076+
return {
2077+
this->template getTrailingObjects<DynamicReplacementSomeDescriptor>(),
2078+
numEntries};
2079+
}
2080+
2081+
public:
2082+
void enableReplacements(const Mutex &lock) const {
2083+
for (auto &replacementEntry : getReplacementEntries())
2084+
replacementEntry.enable(lock);
2085+
}
2086+
};
2087+
2088+
} // anonymous namespace
20182089

20192090
void swift::addImageDynamicReplacementBlockCallback(
2020-
const void *replacements, uintptr_t replacementsSize) {
2091+
const void *replacements, uintptr_t replacementsSize,
2092+
const void *replacementsSome, uintptr_t replacementsSomeSize) {
20212093
auto *automaticReplacements =
20222094
reinterpret_cast<const AutomaticDynamicReplacements *>(replacements);
2023-
DynamicReplacementLock.get().withLock(
2024-
[&] { automaticReplacements->enableReplacements(); });
2095+
const AutomaticDynamicReplacementsSome *someReplacements = nullptr;
2096+
if (replacementsSomeSize) {
2097+
someReplacements =
2098+
reinterpret_cast<const AutomaticDynamicReplacementsSome *>(
2099+
replacementsSome);
2100+
}
2101+
auto &lock = DynamicReplacementLock.get();
2102+
lock.withLock([&] {
2103+
automaticReplacements->enableReplacements();
2104+
if (someReplacements)
2105+
someReplacements->enableReplacements(lock);
2106+
});
20252107
}
20262108

20272109
void swift::swift_enableDynamicReplacementScope(

stdlib/public/runtime/SwiftRT-COFF.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ DECLARE_SWIFT_SECTION(sw5rfst)
4545
DECLARE_SWIFT_SECTION(sw5flmd)
4646
DECLARE_SWIFT_SECTION(sw5asty)
4747
DECLARE_SWIFT_SECTION(sw5repl)
48+
DECLARE_SWIFT_SECTION(sw5reps)
4849
}
4950

5051
namespace {
@@ -72,6 +73,7 @@ static void swift_image_constructor() {
7273
SWIFT_SECTION_RANGE(sw5flmd),
7374
SWIFT_SECTION_RANGE(sw5asty),
7475
SWIFT_SECTION_RANGE(sw5repl),
76+
SWIFT_SECTION_RANGE(sw5reps),
7577
};
7678

7779
#undef SWIFT_SECTION_RANGE

stdlib/public/runtime/SwiftRT-ELF.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ DECLARE_SWIFT_SECTION(swift5_reflstr)
3333
DECLARE_SWIFT_SECTION(swift5_fieldmd)
3434
DECLARE_SWIFT_SECTION(swift5_assocty)
3535
DECLARE_SWIFT_SECTION(swift5_replace)
36+
DECLARE_SWIFT_SECTION(swift5_replac2)
3637
}
3738

3839
#undef DECLARE_SWIFT_SECTION
@@ -63,6 +64,7 @@ static void swift_image_constructor() {
6364
SWIFT_SECTION_RANGE(swift5_fieldmd),
6465
SWIFT_SECTION_RANGE(swift5_assocty),
6566
SWIFT_SECTION_RANGE(swift5_replace),
67+
SWIFT_SECTION_RANGE(swift5_replac2),
6668
};
6769

6870
#undef SWIFT_SECTION_RANGE

test/Interpreter/Inputs/dynamic_replacement_opaque1.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,22 @@ struct Container {
4040
}
4141
}
4242
}
43+
44+
protocol Q {}
45+
46+
struct NewType : Q {}
47+
48+
extension Int : Q {}
49+
50+
public protocol Assoc {
51+
associatedtype A = Int
52+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
53+
func act() -> A
54+
}
55+
56+
struct Test : Assoc {
57+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
58+
func act() -> some Q {
59+
return 1
60+
}
61+
}

test/Interpreter/Inputs/dynamic_replacement_opaque2.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,11 @@ extension Container {
4343
}
4444
}
4545
}
46+
47+
extension Test {
48+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
49+
@_dynamicReplacement(for: act)
50+
func act_r() -> some Q {
51+
return NewType()
52+
}
53+
}

0 commit comments

Comments
 (0)