Skip to content

Commit dcd1732

Browse files
Merge pull request #25616 from aschwaighofer/fix_multi_object_file_replacements_runtime
Fix dynamic replacement runtime when generating replacements from multiple object files
2 parents bb2e003 + d662c5c commit dcd1732

File tree

6 files changed

+162
-4
lines changed

6 files changed

+162
-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: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
// XFAIL: swift_test_mode_optimize
9+
// XFAIL: swift_test_mode_optimize_size
10+
11+
import StdlibUnittest
12+
13+
dynamic func replaceable() -> Int {
14+
return 0
15+
}
16+
17+
dynamic func replaceableInOtherFile() -> Int {
18+
return 0
19+
}
20+
21+
@_dynamicReplacement(for: replaceable())
22+
func replaceable_r() -> Int {
23+
return 1
24+
}
25+
26+
protocol P {}
27+
28+
extension Int : P {}
29+
30+
struct Pair {
31+
var x: Int64 = 0
32+
var y: Int64 = 0
33+
}
34+
35+
extension Pair : P {}
36+
37+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
38+
dynamic func bar(_ x: Int) -> some P {
39+
return x
40+
}
41+
42+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
43+
@_dynamicReplacement(for: bar(_:))
44+
func bar_r(_ x: Int) -> some P {
45+
return Pair()
46+
}
47+
48+
var DynamicallyReplaceable = TestSuite("DynamicallyReplaceable")
49+
50+
DynamicallyReplaceable.test("DynamicallyReplaceable") {
51+
expectEqual(1, replaceable())
52+
expectEqual(2, replaceable1())
53+
expectEqual(3, replaceable2())
54+
expectEqual(7, replaceableInOtherFile())
55+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
56+
expectEqual(16, MemoryLayout.size(ofValue: bar(5)))
57+
expectEqual(16, MemoryLayout.size(ofValue: bar1(5)))
58+
expectEqual(16, MemoryLayout.size(ofValue: bar2(5)))
59+
expectEqual(16, MemoryLayout.size(ofValue: bar3(5)))
60+
}
61+
62+
}
63+
64+
runAllTests()

0 commit comments

Comments
 (0)