Skip to content

Commit b1eea5e

Browse files
authored
Merge pull request #82270 from al45tair/fix-embedded-concurrency
[Concurrency][Embedded] Make sure Embedded Swift links Impl functions. Teach the Embedded Swift compiler to include the Impl functions for the functions that provide Concurrency hooks. Also enable `MainActor` when building Embedded Swift stdlib for WASI.
2 parents c019093 + 31e92db commit b1eea5e

File tree

4 files changed

+65
-12
lines changed

4 files changed

+65
-12
lines changed

include/swift/SIL/SILModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,11 @@ class SILModule {
867867
/// Returns true if linking succeeded, false otherwise.
868868
bool linkFunction(SILFunction *F, LinkingMode LinkMode);
869869

870+
/// Attempt to deserialize witness table for protocol conformance \p PC.
871+
///
872+
/// Returns true if linking succeeded, false otherwise.
873+
bool linkWitnessTable(ProtocolConformance *PC, LinkingMode LinkMode);
874+
870875
/// Check if a given function exists in any of the modules.
871876
/// i.e. it can be linked by linkFunction.
872877
bool hasFunction(StringRef Name);

lib/SIL/IR/SILModule.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,10 @@ bool SILModule::linkFunction(SILFunction *F, SILModule::LinkingMode Mode) {
433433
return SILLinkerVisitor(*this, Mode).processFunction(F);
434434
}
435435

436+
bool SILModule::linkWitnessTable(ProtocolConformance *PC, SILModule::LinkingMode Mode) {
437+
return SILLinkerVisitor(*this, Mode).processConformance(ProtocolConformanceRef(PC));
438+
}
439+
436440
bool SILModule::hasFunction(StringRef Name) {
437441
if (lookUpFunction(Name))
438442
return true;

lib/SILOptimizer/UtilityPasses/Link.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "swift/AST/ProtocolConformance.h"
1314
#include "swift/SILOptimizer/PassManager/Passes.h"
1415
#include "swift/SILOptimizer/PassManager/Transforms.h"
1516
#include "swift/SIL/SILModule.h"
@@ -48,6 +49,7 @@ class SILLinker : public SILModuleTransform {
4849
// (swift_retain, etc.). Link them in so they can be referenced in IRGen.
4950
if (M.getOptions().EmbeddedSwift && LinkEmbeddedRuntime) {
5051
linkEmbeddedRuntimeFromStdlib();
52+
linkEmbeddedConcurrency();
5153
}
5254

5355
// In embedded Swift, we need to explicitly link any @_used globals and
@@ -80,6 +82,32 @@ class SILLinker : public SILModuleTransform {
8082
linkEmbeddedRuntimeFunctionByName("swift_retainCount", { RefCounting });
8183
}
8284

85+
void linkEmbeddedConcurrency() {
86+
using namespace RuntimeConstants;
87+
88+
// Note: we ignore errors here, because, depending on the exact situation
89+
//
90+
// (a) We might not have Concurrency anyway, and
91+
//
92+
// (b) The Impl function might be implemented in C++.
93+
//
94+
// Also, the hook Impl functions are marked as internal, unlike the
95+
// runtime functions, which are public.
96+
97+
#define SWIFT_CONCURRENCY_HOOK(RETURNS, NAME, ...) \
98+
linkUsedFunctionByName(#NAME "Impl", SILLinkage::HiddenExternal)
99+
#define SWIFT_CONCURRENCY_HOOK0(RETURNS, NAME) \
100+
linkUsedFunctionByName(#NAME "Impl", SILLinkage::HiddenExternal)
101+
102+
#include "swift/Runtime/ConcurrencyHooks.def"
103+
104+
linkUsedFunctionByName("swift_task_asyncMainDrainQueueImpl",
105+
SILLinkage::HiddenExternal);
106+
linkUsedFunctionByName("swift_createDefaultExecutors",
107+
SILLinkage::HiddenExternal);
108+
linkEmbeddedRuntimeWitnessTables();
109+
}
110+
83111
void linkEmbeddedRuntimeFunctionByName(StringRef name,
84112
ArrayRef<RuntimeEffect> effects) {
85113
SILModule &M = *getModule();
@@ -96,6 +124,23 @@ class SILLinker : public SILModuleTransform {
96124
linkUsedFunctionByName(name, SILLinkage::PublicExternal);
97125
}
98126

127+
void linkEmbeddedRuntimeWitnessTables() {
128+
SILModule &M = *getModule();
129+
130+
auto *mainActor = M.getASTContext().getMainActorDecl();
131+
if (mainActor) {
132+
for (auto *PC : mainActor->getAllConformances()) {
133+
auto *ProtoDecl = PC->getProtocol();
134+
if (ProtoDecl->getName().str() == "Actor") {
135+
M.linkWitnessTable(PC, SILModule::LinkingMode::LinkAll);
136+
if (auto *WT = M.lookUpWitnessTable(PC)) {
137+
WT->setLinkage(SILLinkage::Public);
138+
}
139+
}
140+
}
141+
}
142+
}
143+
99144
SILFunction *linkUsedFunctionByName(StringRef name,
100145
std::optional<SILLinkage> Linkage) {
101146
SILModule &M = *getModule();
@@ -134,7 +179,7 @@ class SILLinker : public SILModuleTransform {
134179
// linked global variable.
135180
if (GV->isDefinition())
136181
GV->setLinkage(SILLinkage::Public);
137-
182+
138183
return GV;
139184
}
140185

stdlib/public/Concurrency/Executor.swift

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ public protocol Executor: AnyObject, Sendable {
3636
func enqueue(_ job: consuming ExecutorJob)
3737
#endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
3838

39-
#if !$Embedded
39+
#if os(WASI) || !$Embedded
4040
/// `true` if this is the main executor.
4141
@available(StdlibDeploymentTarget 6.2, *)
4242
var isMainExecutor: Bool { get }
43-
#endif
43+
#endif // os(WASI) || !$Embedded
4444
}
4545

4646
@available(StdlibDeploymentTarget 6.2, *)
@@ -144,13 +144,12 @@ extension Executor where Self: Equatable {
144144
}
145145

146146
extension Executor {
147-
148-
#if !$Embedded
147+
#if os(WASI) || !$Embedded
149148
// This defaults to `false` so that existing third-party Executor
150149
// implementations will work as expected.
151150
@available(StdlibDeploymentTarget 6.2, *)
152151
public var isMainExecutor: Bool { false }
153-
#endif
152+
#endif // os(WASI) || !$Embedded
154153

155154
}
156155

@@ -368,10 +367,10 @@ public protocol SerialExecutor: Executor {
368367
@available(StdlibDeploymentTarget 6.0, *)
369368
extension SerialExecutor {
370369

371-
#if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
370+
#if os(WASI) || (!$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
372371
@available(StdlibDeploymentTarget 6.2, *)
373372
public var isMainExecutor: Bool { return MainActor.executor._isSameExecutor(self) }
374-
#endif
373+
#endif // os(WASI) || (!$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
375374

376375
@available(StdlibDeploymentTarget 6.0, *)
377376
public func checkIsolated() {
@@ -579,11 +578,11 @@ public protocol MainExecutor: RunLoopExecutor, SerialExecutor {
579578
/// executors.
580579
@available(StdlibDeploymentTarget 6.2, *)
581580
public protocol ExecutorFactory {
582-
#if !$Embedded
581+
#if os(WASI) || !$Embedded
583582
/// Constructs and returns the main executor, which is started implicitly
584583
/// by the `async main` entry point and owns the "main" thread.
585584
static var mainExecutor: any MainExecutor { get }
586-
#endif
585+
#endif // os(WASI) || !$Embedded
587586

588587
/// Constructs and returns the default or global executor, which is the
589588
/// default place in which we run tasks.
@@ -596,9 +595,9 @@ typealias DefaultExecutorFactory = PlatformExecutorFactory
596595
@available(StdlibDeploymentTarget 6.2, *)
597596
@_silgen_name("swift_createExecutors")
598597
public func _createExecutors<F: ExecutorFactory>(factory: F.Type) {
599-
#if !$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
598+
#if os(WASI) || (!$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
600599
MainActor._executor = factory.mainExecutor
601-
#endif
600+
#endif // os(WASI) || (!$Embedded && !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY)
602601
Task._defaultExecutor = factory.defaultExecutor
603602
}
604603

0 commit comments

Comments
 (0)