Skip to content

Commit fb08153

Browse files
committed
Fix dynamic replacement runtime when generating replacements from multiple object files
The sections with the replacements get merged and we need to consider all replacements. SR-10947 rdar://51913012
1 parent 69c643b commit fb08153

File tree

6 files changed

+159
-4
lines changed

6 files changed

+159
-4
lines changed

lib/IRGen/GenDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,6 +1515,7 @@ void IRGenerator::emitDynamicReplacements() {
15151515
autoReplacements.addInt32(1); // number of replacement entries.
15161516
auto autoReplacementsArray = autoReplacements.beginArray();
15171517
autoReplacementsArray.addRelativeAddress(var);
1518+
autoReplacementsArray.addInt32(0); // unused flags.
15181519
autoReplacementsArray.finishAndAddTo(autoReplacements);
15191520
auto autoReplVar = autoReplacements.finishAndCreateGlobal(
15201521
"\x01l_auto_dynamic_replacements", IGM.getPointerAlignment(),

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,8 @@ class AutomaticDynamicReplacements
20442044
for (auto &replacementEntry : getReplacementEntries())
20452045
replacementEntry.enable();
20462046
}
2047+
2048+
uint32_t getNumScopes() const { return numScopes; }
20472049
};
20482050

20492051
/// A map from original to replaced opaque type descriptor of a some type.
@@ -2083,26 +2085,63 @@ class AutomaticDynamicReplacementsSome
20832085
for (auto &replacementEntry : getReplacementEntries())
20842086
replacementEntry.enable(lock);
20852087
}
2088+
uint32_t getNumEntries() const { return numEntries; }
20862089
};
20872090

20882091
} // anonymous namespace
20892092

20902093
void swift::addImageDynamicReplacementBlockCallback(
20912094
const void *replacements, uintptr_t replacementsSize,
20922095
const void *replacementsSome, uintptr_t replacementsSomeSize) {
2096+
20932097
auto *automaticReplacements =
20942098
reinterpret_cast<const AutomaticDynamicReplacements *>(replacements);
2099+
20952100
const AutomaticDynamicReplacementsSome *someReplacements = nullptr;
20962101
if (replacementsSomeSize) {
20972102
someReplacements =
20982103
reinterpret_cast<const AutomaticDynamicReplacementsSome *>(
20992104
replacementsSome);
21002105
}
2106+
2107+
auto sizeOfCurrentEntry = sizeof(AutomaticDynamicReplacements) +
2108+
(automaticReplacements->getNumScopes() *
2109+
sizeof(AutomaticDynamicReplacementEntry));
2110+
auto sizeOfCurrentSomeEntry =
2111+
replacementsSomeSize == 0
2112+
? 0
2113+
: sizeof(AutomaticDynamicReplacementsSome) +
2114+
(someReplacements->getNumEntries() *
2115+
sizeof(DynamicReplacementSomeDescriptor));
2116+
21012117
auto &lock = DynamicReplacementLock.get();
21022118
lock.withLock([&] {
2103-
automaticReplacements->enableReplacements();
2104-
if (someReplacements)
2119+
auto endOfAutomaticReplacements =
2120+
((const char *)automaticReplacements) + replacementsSize;
2121+
while (((const char *)automaticReplacements) < endOfAutomaticReplacements) {
2122+
automaticReplacements->enableReplacements();
2123+
automaticReplacements =
2124+
reinterpret_cast<const AutomaticDynamicReplacements *>(
2125+
((const char *)automaticReplacements) + sizeOfCurrentEntry);
2126+
if ((const char*)automaticReplacements < endOfAutomaticReplacements)
2127+
sizeOfCurrentEntry = sizeof(AutomaticDynamicReplacements) +
2128+
(automaticReplacements->getNumScopes() *
2129+
sizeof(AutomaticDynamicReplacementEntry));
2130+
}
2131+
if (!replacementsSomeSize)
2132+
return;
2133+
auto endOfSomeReplacements =
2134+
((const char *)someReplacements) + replacementsSomeSize;
2135+
while (((const char *)someReplacements) < endOfSomeReplacements) {
21052136
someReplacements->enableReplacements(lock);
2137+
someReplacements =
2138+
reinterpret_cast<const AutomaticDynamicReplacementsSome *>(
2139+
((const char *)someReplacements) + sizeOfCurrentSomeEntry);
2140+
if ((const char*) someReplacements < endOfSomeReplacements)
2141+
sizeOfCurrentSomeEntry = sizeof(AutomaticDynamicReplacementsSome) +
2142+
(someReplacements->getNumEntries() *
2143+
sizeof(DynamicReplacementSomeDescriptor));
2144+
}
21062145
});
21072146
}
21082147

test/IRGen/dynamic_replaceable.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
// CHECK: %swift.dyn_repl_link_entry* @test_replacementTX
1818
// CHECK: i32 0 }] }, section "__TEXT,__const"
1919

20-
// CHECK: @"\01l_auto_dynamic_replacements" = private constant { i32, i32, [1 x i32] }
20+
// CHECK: @"\01l_auto_dynamic_replacements" = private constant { i32, i32, [2 x i32] }
2121
// CHECK: { i32 0, i32 1,
22-
// CHECK: [1 x i32] [{{.*}}@"\01l_unnamed_dynamic_replacements"{{.*}}]
22+
// CHECK: [2 x i32] [{{.*}}@"\01l_unnamed_dynamic_replacements"{{.*}}, i32 0]
2323
// CHECK: }, section "__TEXT, __swift5_replace, regular, no_dead_strip"
2424

2525
// CHECK-LABEL: define swiftcc void @test_dynamically_replaceable()
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
dynamic func replaceable1() -> Int {
2+
return 0
3+
}
4+
5+
@_dynamicReplacement(for: replaceable1())
6+
func replaceable1_r() -> Int {
7+
return 2
8+
}
9+
10+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
11+
dynamic func bar1(_ x: Int) -> some P {
12+
return x
13+
}
14+
15+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
16+
@_dynamicReplacement(for: bar1(_:))
17+
func bar1_r(_ x: Int) -> some P {
18+
return Pair()
19+
}
20+
21+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
22+
dynamic func bar2(_ x: Int) -> some P {
23+
return x
24+
}
25+
26+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
27+
@_dynamicReplacement(for: bar2(_:))
28+
func bar2_r(_ x: Int) -> some P {
29+
return Pair()
30+
}
31+
32+
@_dynamicReplacement(for: replaceableInOtherFile())
33+
func replaceableInOtherFile_r() -> Int {
34+
return 7
35+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
dynamic func replaceable2() -> Int {
2+
return 0
3+
}
4+
5+
@_dynamicReplacement(for: replaceable2())
6+
func replaceable2_r() -> Int {
7+
return 3
8+
}
9+
10+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
11+
dynamic func bar3(_ x: Int) -> some P {
12+
return x
13+
}
14+
15+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
16+
@_dynamicReplacement(for: bar3(_:))
17+
func bar3_r(_ x: Int) -> some P {
18+
return Pair()
19+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -o %t/main %s %S/Inputs/dynamic_replacement_multi_file_A.swift %S/Inputs/dynamic_replacement_multi_file_B.swift -swift-version 5
3+
// RUN: %target-codesign %t/main
4+
// RUN: %target-run %t/main
5+
6+
// REQUIRES: executable_test
7+
8+
import StdlibUnittest
9+
10+
dynamic func replaceable() -> Int {
11+
return 0
12+
}
13+
14+
dynamic func replaceableInOtherFile() -> Int {
15+
return 0
16+
}
17+
18+
@_dynamicReplacement(for: replaceable())
19+
func replaceable_r() -> Int {
20+
return 1
21+
}
22+
23+
protocol P {}
24+
25+
extension Int : P {}
26+
27+
struct Pair {
28+
var x: Int64 = 0
29+
var y: Int64 = 0
30+
}
31+
32+
extension Pair : P {}
33+
34+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
35+
dynamic func bar(_ x: Int) -> some P {
36+
return x
37+
}
38+
39+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
40+
@_dynamicReplacement(for: bar(_:))
41+
func bar_r(_ x: Int) -> some P {
42+
return Pair()
43+
}
44+
45+
var DynamicallyReplaceable = TestSuite("DynamicallyReplaceable")
46+
47+
DynamicallyReplaceable.test("DynamicallyReplaceable") {
48+
expectEqual(1, replaceable())
49+
expectEqual(2, replaceable1())
50+
expectEqual(3, replaceable2())
51+
expectEqual(7, replaceableInOtherFile())
52+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
53+
expectEqual(16, MemoryLayout.size(ofValue: bar(5)))
54+
expectEqual(16, MemoryLayout.size(ofValue: bar1(5)))
55+
expectEqual(16, MemoryLayout.size(ofValue: bar2(5)))
56+
expectEqual(16, MemoryLayout.size(ofValue: bar3(5)))
57+
}
58+
59+
}
60+
61+
runAllTests()

0 commit comments

Comments
 (0)