Skip to content

Commit e276472

Browse files
committed
[AsyncCC] Resolve metadata from class instances.
Metadata for an instance of a type is resolved by extracting it from an instance of the class. When doing method lookup for an instance method of a resilient class, the lowered self value was being obtained from the list of arguments directly by indexing. That does not apply to async functions where self is embedded within the async context. Here, the self parameter is extracted from the async context so that the metadata can in turn be extracted from it. rdar://problem/71260862
1 parent 0462e35 commit e276472

File tree

4 files changed

+98
-9
lines changed

4 files changed

+98
-9
lines changed

lib/IRGen/GenThunk.cpp

+31-9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "ClassMetadataVisitor.h"
2121
#include "ConstantBuilder.h"
2222
#include "Explosion.h"
23+
#include "GenCall.h"
2324
#include "GenClass.h"
2425
#include "GenDecl.h"
2526
#include "GenHeap.h"
@@ -31,6 +32,7 @@
3132
#include "MetadataLayout.h"
3233
#include "ProtocolInfo.h"
3334
#include "Signature.h"
35+
#include "swift/AST/GenericEnvironment.h"
3436
#include "swift/IRGen/Linking.h"
3537
#include "swift/SIL/SILDeclRef.h"
3638
#include "llvm/IR/Function.h"
@@ -79,14 +81,32 @@ static FunctionPointer lookupMethod(IRGenFunction &IGF, SILDeclRef declRef) {
7981
// Load the metadata, or use the 'self' value if we have a static method.
8082
llvm::Value *self;
8183

82-
// Non-throwing class methods always have the 'self' parameter at the end.
83-
// Throwing class methods have 'self' right before the error parameter.
84-
//
85-
// FIXME: Should find a better way of expressing this.
86-
if (funcTy->hasErrorResult())
87-
self = (IGF.CurFn->arg_end() - 2);
88-
else
89-
self = (IGF.CurFn->arg_end() - 1);
84+
if (funcTy->isAsync()) {
85+
auto originalType = funcTy;
86+
auto forwardingSubstitutionMap =
87+
decl->getGenericEnvironment()
88+
? decl->getGenericEnvironment()->getForwardingSubstitutionMap()
89+
: SubstitutionMap();
90+
auto substitutedType = originalType->substGenericArgs(
91+
IGF.IGM.getSILModule(), forwardingSubstitutionMap,
92+
IGF.IGM.getMaximalTypeExpansionContext());
93+
auto layout = getAsyncContextLayout(IGF.IGM, originalType, substitutedType,
94+
forwardingSubstitutionMap);
95+
assert(layout.hasLocalContext());
96+
auto context = layout.emitCastTo(IGF, IGF.getAsyncContext());
97+
auto localContextAddr =
98+
layout.getLocalContextLayout().project(IGF, context, llvm::None);
99+
self = IGF.Builder.CreateLoad(localContextAddr);
100+
} else {
101+
// Non-throwing class methods always have the 'self' parameter at the end.
102+
// Throwing class methods have 'self' right before the error parameter.
103+
//
104+
// FIXME: Should find a better way of expressing this.
105+
if (funcTy->hasErrorResult())
106+
self = (IGF.CurFn->arg_end() - 2);
107+
else
108+
self = (IGF.CurFn->arg_end() - 1);
109+
}
90110

91111
auto selfTy = funcTy->getSelfParameter().getSILStorageType(
92112
IGF.IGM.getSILModule(), funcTy, IGF.IGM.getMaximalTypeExpansionContext());
@@ -109,13 +129,15 @@ void IRGenModule::emitDispatchThunk(SILDeclRef declRef) {
109129
}
110130

111131
IRGenFunction IGF(*this, f);
132+
IGF.setAsync(declRef.getAbstractFunctionDecl()->hasAsync());
112133

113134
// Look up the method.
114135
auto fn = lookupMethod(IGF, declRef);
115136

116137
// Call the witness, forwarding all of the parameters.
117138
auto params = IGF.collectParameters();
118-
auto result = IGF.Builder.CreateCall(fn, params.claimAll());
139+
auto result =
140+
IGF.Builder.CreateCall(fn.getAsFunction(IGF), params.claimAll());
119141

120142
// Return the result, if we have one.
121143
if (result->getType()->isVoidTy())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import _Concurrency
2+
3+
public class Clazz {
4+
public init() {}
5+
public func classinstanceVoidToVoid() async {
6+
print(self)
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift-dylib(%t/%target-library-name(PrintShims)) %S/../../Inputs/print-shims.swift -module-name PrintShims -emit-module -emit-module-path %t/PrintShims.swiftmodule
3+
// RUN: %target-codesign %t/%target-library-name(PrintShims)
4+
// RUN: %target-build-swift-dylib(%t/%target-library-name(ResilientClass)) %S/Inputs/class-1instance-void_to_void.swift -Xfrontend -enable-experimental-concurrency -module-name ResilientClass -emit-module -emit-module-path %t/ResilientClass.swiftmodule
5+
// RUN: %target-codesign %t/%target-library-name(ResilientClass)
6+
// RUN: %target-build-swift -Xfrontend -enable-experimental-concurrency -parse-sil %s -emit-ir -I %t -L %t -lPrintShim -lResilientClass | %FileCheck %s --check-prefix=CHECK-LL
7+
// RUN: %target-build-swift -Xfrontend -enable-experimental-concurrency -parse-sil %s -module-name main -o %t/main -I %t -L %t -lPrintShims -lResilientClass %target-rpath(%t)
8+
// RUN: %target-codesign %t/main
9+
// RUN: %target-run %t/main %t/%target-library-name(PrintShims) %t/%target-library-name(ResilientClass) | %FileCheck %s
10+
11+
// REQUIRES: executable_test
12+
// REQUIRES: swift_test_mode_optimize_none
13+
// REQUIRES: concurrency
14+
// UNSUPPORTED: use_os_stdlib
15+
// UNSUPPORTED: CPU=arm64e
16+
17+
18+
import Builtin
19+
import Swift
20+
import PrintShims
21+
import _Concurrency
22+
import ResilientClass
23+
24+
sil public_external [exact_self_class] @$s14ResilientClass5ClazzCACycfC : $@convention(method) (@thick Clazz.Type) -> @owned Clazz
25+
26+
// Defined in _Concurrency
27+
sil public_external @$s12_Concurrency8runAsyncyyyyYcF : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
28+
29+
// CHECK-LL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_case(%swift.task* {{%[0-9]+}}, %swift.executor* {{%[0-9]+}}, %swift.context* {{%[0-9]+}}) {{#[0-9]*}} {
30+
sil @test_case : $@convention(thin) @async () -> () {
31+
%s_type = metatype $@thick Clazz.Type
32+
%allocating_init = function_ref @$s14ResilientClass5ClazzCACycfC : $@convention(method) (@thick Clazz.Type) -> @owned Clazz
33+
%instance = apply %allocating_init(%s_type) : $@convention(method) (@thick Clazz.Type) -> @owned Clazz
34+
%classinstanceVoidToVoid = class_method %instance : $Clazz, #Clazz.classinstanceVoidToVoid : (Clazz) -> () async -> (), $@convention(method) @async (@guaranteed Clazz) -> ()
35+
strong_retain %instance : $Clazz
36+
%result = apply %classinstanceVoidToVoid(%instance) : $@convention(method) @async (@guaranteed Clazz) -> () // CHECK: ResilientClass.Clazz
37+
strong_release %instance : $Clazz
38+
39+
%out = tuple ()
40+
return %out : $()
41+
}
42+
43+
sil @main : $@async @convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
44+
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
45+
46+
%2 = function_ref @test_case : $@convention(thin) @async () -> ()
47+
%3 = thin_to_thick_function %2 : $@convention(thin) @async () -> () to $@async @callee_guaranteed () -> ()
48+
%4 = function_ref @$s12_Concurrency8runAsyncyyyyYcF : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
49+
%5 = apply %4(%3) : $@convention(thin) (@guaranteed @async @callee_guaranteed () -> ()) -> ()
50+
51+
%6 = integer_literal $Builtin.Int32, 0
52+
%7 = struct $Int32 (%6 : $Builtin.Int32)
53+
return %7 : $Int32
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %target-swift-frontend %s -emit-ir -enable-library-evolution -enable-experimental-concurrency
2+
3+
public class X {
4+
public func f() async { }
5+
}

0 commit comments

Comments
 (0)