Skip to content

Commit 30907a9

Browse files
committed
MandatoryPerformanceOptimizations: make sure to handle de-serialized vtable methods
When de-serializing a function and this function allocates a class, the methods of the de-serialized vtable must be handled, too. Fixes an IRGen crash rdar://152311945
1 parent d49dd18 commit 30907a9

File tree

2 files changed

+83
-13
lines changed

2 files changed

+83
-13
lines changed

SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ private func optimizeFunctionsTopDown(using worklist: inout FunctionWorklist,
6464
// We need handle this case with a function signature optimization.
6565
removeMetatypeArgumentsInCallees(of: f, moduleContext)
6666

67-
worklist.addCallees(of: f)
67+
worklist.addCallees(of: f, moduleContext)
6868
}
6969
}
7070

@@ -496,29 +496,41 @@ fileprivate struct FunctionWorklist {
496496
return
497497
}
498498

499-
mutating func addCallees(of function: Function) {
499+
mutating func addCallees(of function: Function, _ context: ModulePassContext) {
500500
for inst in function.instructions {
501501
switch inst {
502-
case let apply as ApplySite:
503-
if let callee = apply.referencedFunction {
504-
pushIfNotVisited(callee)
502+
case let fri as FunctionRefInst:
503+
pushIfNotVisited(fri.referencedFunction)
504+
case let alloc as AllocRefInst:
505+
if context.options.enableEmbeddedSwift {
506+
addVTableMethods(forClassType: alloc.type, context)
505507
}
506-
case let bi as BuiltinInst:
507-
switch bi.id {
508-
case .Once, .OnceWithContext:
509-
if let fri = bi.operands[1].value as? FunctionRefInst {
510-
pushIfNotVisited(fri.referencedFunction)
508+
case let metatype as MetatypeInst:
509+
if context.options.enableEmbeddedSwift {
510+
let instanceType = metatype.type.loweredInstanceTypeOfMetatype(in: function)
511+
if instanceType.isClass {
512+
addVTableMethods(forClassType: instanceType, context)
511513
}
512-
break;
513-
default:
514-
break
515514
}
515+
516516
default:
517517
break
518518
}
519519
}
520520
}
521521

522+
mutating func addVTableMethods(forClassType classType: Type, _ context: ModulePassContext) {
523+
guard let vtable = classType.isGenericAtAnyLevel ?
524+
context.lookupSpecializedVTable(for: classType) :
525+
context.lookupVTable(for: classType.nominal!)
526+
else {
527+
return
528+
}
529+
for entry in vtable.entries where !entry.implementation.isGeneric {
530+
pushIfNotVisited(entry.implementation)
531+
}
532+
}
533+
522534
mutating func addWitnessMethods(of witnessTable: WitnessTable) {
523535
for entry in witnessTable.entries {
524536
if case .method(_, let witness) = entry,
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -enable-experimental-feature Embedded -c -I%t -parse-as-library %t/MyModule.swift -o %t/MyModule.o -emit-module -emit-module-path %t/MyModule.swiftmodule -emit-empty-object-file
5+
// RUN: %target-swift-frontend -enable-experimental-feature Embedded -c -I%t %t/Main.swift -o %t/Main.o
6+
// RUN: %target-clang %t/Main.o %t/MyModule.o -o %t/a.out
7+
// RUN: %target-run %t/a.out | %FileCheck %s
8+
9+
// REQUIRES: executable_test
10+
// REQUIRES: swift_feature_Embedded
11+
12+
//--- MyModule.swift
13+
14+
public class C<T> {
15+
public func foo() {
16+
let x = X<Int>(x: 27)
17+
x.bar()
18+
}
19+
}
20+
21+
class D<T>: C<T> {
22+
override public func foo() {
23+
print("D")
24+
}
25+
}
26+
27+
class X<T: BinaryInteger> {
28+
var x: T
29+
30+
init(x: T) { self.x = x }
31+
32+
func bar() {
33+
print(x)
34+
}
35+
}
36+
37+
class Y<T: BinaryInteger>: X<T> {
38+
override func bar() {
39+
}
40+
}
41+
42+
@inline(never)
43+
public func create<T>(_ t: T.Type) -> C<T> {
44+
return C<T>()
45+
}
46+
47+
//--- Main.swift
48+
49+
import MyModule
50+
51+
@inline(never)
52+
public func testit() {
53+
let c = create(Int.self)
54+
c.foo()
55+
}
56+
57+
// CHECK: 27
58+
testit()

0 commit comments

Comments
 (0)