Skip to content

Commit 6f68a86

Browse files
authored
Merge pull request #80530 from eeckstein/fix-sil-linker
embedded: fix two problems in the SILLinker
2 parents 6eaa07a + 14ff3ea commit 6f68a86

File tree

4 files changed

+92
-2
lines changed

4 files changed

+92
-2
lines changed

lib/SIL/IR/Linker.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,10 @@ void SILLinkerVisitor::visitProtocolConformance(
342342
// reading in most conformances until we need them for devirtualization.
343343
// However, we *must* pull in shared clang-importer-derived conformances
344344
// we potentially use, since we may not otherwise have a local definition.
345-
if (mustDeserializeProtocolConformance(Mod, c))
345+
if ((isEmbedded && referencedFromInitExistential) ||
346+
mustDeserializeProtocolConformance(Mod, c)) {
346347
visitProtocolConformance(c, referencedFromInitExistential);
348+
}
347349
};
348350

349351
// For each entry in the witness table...
@@ -427,6 +429,24 @@ void SILLinkerVisitor::visitInitExistentialRefInst(
427429
}
428430
}
429431

432+
void SILLinkerVisitor::visitBuiltinInst(BuiltinInst *bi) {
433+
switch (bi->getBuiltinInfo().ID) {
434+
case BuiltinValueKind::BuildOrdinaryTaskExecutorRef:
435+
case BuiltinValueKind::BuildOrdinarySerialExecutorRef:
436+
case BuiltinValueKind::BuildComplexEqualitySerialExecutorRef:
437+
if (Mod.getOptions().EmbeddedSwift) {
438+
// Those builtins act like init_existential_ref instructions and therefore
439+
// it's important to have the Executor witness tables available in embedded
440+
// mode.
441+
auto executorConf = bi->getSubstitutions().getConformances()[0];
442+
visitProtocolConformance(executorConf, true);
443+
}
444+
break;
445+
default:
446+
break;
447+
}
448+
}
449+
430450
void SILLinkerVisitor::visitAllocRefDynamicInst(AllocRefDynamicInst *ARI) {
431451
if (!isLinkAll())
432452
return;

lib/SIL/IR/Linker.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class SILLinkerVisitor : public SILInstructionVisitor<SILLinkerVisitor, void> {
129129
}
130130
void visitInitExistentialAddrInst(InitExistentialAddrInst *IEI);
131131
void visitInitExistentialRefInst(InitExistentialRefInst *IERI);
132+
void visitBuiltinInst(BuiltinInst *bi);
132133
void visitAllocRefInst(AllocRefInst *ARI);
133134
void visitAllocRefDynamicInst(AllocRefDynamicInst *ARI);
134135
void visitMetatypeInst(MetatypeInst *MI);
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %{python} %utils/split_file.py -o %t %s
3+
4+
// RUN: %target-swift-frontend -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -enable-experimental-feature Embedded -parse-as-library
5+
// RUN: %target-swift-frontend -c -I %t %t/Main.swift -enable-experimental-feature Embedded -o %t/a.o -parse-as-library
6+
// RUN: %target-clang %t/a.o -o %t/a.out -L%swift_obj_root/lib/swift/embedded/%target-cpu-apple-macos -lswift_Concurrency -lswift_ConcurrencyDefaultExecutor -dead_strip
7+
// RUN: %target-run %t/a.out | %FileCheck %s
8+
9+
// REQUIRES: swift_in_compiler
10+
// REQUIRES: executable_test
11+
// REQUIRES: OS=macosx
12+
// REQUIRES: swift_feature_Embedded
13+
14+
// BEGIN MyModule.swift
15+
16+
import _Concurrency
17+
18+
nonisolated(unsafe) var glob: UnsafeMutableRawPointer? = nil
19+
nonisolated(unsafe) var job: UnownedJob? = nil
20+
21+
public final class MyCustomExecutor: SerialExecutor, @unchecked Sendable {
22+
private init() {}
23+
24+
nonisolated(unsafe)
25+
public static var shared: MyCustomExecutor = MyCustomExecutor()
26+
27+
public static func installGlobalExecutor() {
28+
let fn: @convention(thin) () -> () = {
29+
MyCustomExecutor.shared.unsafeEnqueue(job!)
30+
}
31+
glob = unsafeBitCast(fn, to: UnsafeMutableRawPointer?.self)
32+
}
33+
34+
private func enqueue(_ job: UnownedJob, withDelay nanoseconds: UInt64) {}
35+
36+
private func unsafeEnqueue(_ job: UnownedJob) {
37+
job.runSynchronously(on: self.asUnownedSerialExecutor())
38+
}
39+
40+
public func enqueue(_ job: consuming ExecutorJob) {
41+
unsafeEnqueue(UnownedJob(job))
42+
}
43+
44+
public func asUnownedSerialExecutor() -> UnownedSerialExecutor {
45+
return UnownedSerialExecutor(ordinary: self)
46+
}
47+
}
48+
49+
// BEGIN Main.swift
50+
51+
import MyModule
52+
import _Concurrency
53+
54+
@main
55+
struct Entrypoint {
56+
static func main() async {
57+
MyCustomExecutor.installGlobalExecutor()
58+
print("OK!")
59+
}
60+
}
61+
62+
// CHECK: OK!

test/embedded/existential-class-bound8.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99

1010
// BEGIN MyModule.swift
1111

12-
public protocol ClassBound: AnyObject {
12+
public protocol Base: AnyObject {
13+
func bar()
14+
}
15+
16+
public protocol ClassBound: Base {
1317
func foo()
1418
}
1519

@@ -18,6 +22,7 @@ class MyGenericClass<T> {
1822
init(typ: String) { self.typ = typ }
1923
}
2024
extension MyGenericClass: ClassBound {
25+
func bar() { print("MyGenericClass<\(typ)>.bar()") }
2126
func foo() { print("MyGenericClass<\(typ)>.foo()") }
2227
}
2328

@@ -32,3 +37,5 @@ import MyModule
3237
var arr: [any ClassBound] = [factory()]
3338
arr[0].foo()
3439
// CHECK: MyGenericClass<String>.foo()
40+
arr[0].foo()
41+
// CHECK: MyGenericClass<String>.bar()

0 commit comments

Comments
 (0)