Skip to content

Commit 10e3d2e

Browse files
committed
Change _wait(_throwing) ABIs to reduce code size
Changes the task, taskGroup, asyncLet wait funtion call ABIs. To reduce code size pass the context parameters and resumption function as arguments to the wait function. This means that the suspend point does not need to store parent context and resumption to the suspend point's context. ``` void swift_task_future_wait_throwing( OpaqueValue * result, SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, AsyncTask *task, ThrowingTaskFutureWaitContinuationFunction *resume, AsyncContext *callContext); ``` The runtime passes the caller context to the resume entry point saving the load of the parent context in the resumption function. This patch adds a `Metadata *` field to `GroupImpl`. The await entry pointer no longer pass the metadata pointer and there is a path through the runtime where the task future is no longer available.
1 parent 6c51fc4 commit 10e3d2e

26 files changed

+312
-272
lines changed

include/swift/ABI/Executor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ using TaskContinuationFunction =
128128
SWIFT_CC(swiftasync)
129129
void (SWIFT_ASYNC_CONTEXT AsyncContext *);
130130

131+
using ThrowingTaskFutureWaitContinuationFunction =
132+
SWIFT_CC(swiftasync)
133+
void (SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT void *);
134+
135+
131136
template <class AsyncSignature>
132137
class AsyncFunctionPointer;
133138
template <class AsyncSignature>

include/swift/Runtime/Concurrency.h

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,6 @@ swift_task_escalate(AsyncTask *task, JobPriority newPriority);
125125
// TODO: "async let wait" and "async let destroy" would be expressed
126126
// similar to like TaskFutureWait;
127127

128-
/// This matches the ABI of a closure `<T>(Builtin.NativeObject) async -> T`
129-
using TaskFutureWaitSignature =
130-
SWIFT_CC(swiftasync)
131-
void(OpaqueValue *,
132-
SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *, Metadata *);
133-
134128
/// Wait for a non-throwing future task to complete.
135129
///
136130
/// This can be called from any thread. Its Swift signature is
@@ -141,12 +135,9 @@ using TaskFutureWaitSignature =
141135
/// \endcode
142136
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
143137
void swift_task_future_wait(OpaqueValue *,
144-
SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *, Metadata *);
145-
146-
using TaskFutureWaitThrowingSignature =
147-
SWIFT_CC(swiftasync)
148-
void(OpaqueValue *,
149-
SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *, Metadata *);
138+
SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *,
139+
TaskContinuationFunction *,
140+
AsyncContext *);
150141

151142
/// Wait for a potentially-throwing future task to complete.
152143
///
@@ -157,15 +148,12 @@ using TaskFutureWaitThrowingSignature =
157148
/// async throws -> Success
158149
/// \endcode
159150
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
160-
void swift_task_future_wait_throwing(OpaqueValue *,
161-
SWIFT_ASYNC_CONTEXT AsyncContext *,
162-
AsyncTask *, Metadata *);
163-
164-
using TaskGroupFutureWaitThrowingSignature =
165-
SWIFT_CC(swiftasync)
166-
void(OpaqueValue *,
167-
SWIFT_ASYNC_CONTEXT AsyncContext *, AsyncTask *, TaskGroup *,
168-
const Metadata *successType);
151+
void swift_task_future_wait_throwing(
152+
OpaqueValue *,
153+
SWIFT_ASYNC_CONTEXT AsyncContext *,
154+
AsyncTask *,
155+
ThrowingTaskFutureWaitContinuationFunction *,
156+
AsyncContext *);
169157

170158
/// Wait for a readyQueue of a Channel to become non empty.
171159
///
@@ -180,8 +168,9 @@ SWIFT_CC(swiftasync)
180168
SWIFT_EXPORT_FROM(swift_Concurrency)
181169
SWIFT_CC(swiftasync)
182170
void swift_taskGroup_wait_next_throwing(
183-
OpaqueValue *resultPointer, SWIFT_ASYNC_CONTEXT AsyncContext *rawContext,
184-
TaskGroup *group, const Metadata *successType);
171+
OpaqueValue *resultPointer, SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
172+
TaskGroup *group, ThrowingTaskFutureWaitContinuationFunction *resumeFn,
173+
AsyncContext *callContext);
185174

186175
/// Initialize a `TaskGroup` in the passed `group` memory location.
187176
/// The caller is responsible for retaining and managing the group's lifecycle.
@@ -192,7 +181,7 @@ void swift_taskGroup_wait_next_throwing(
192181
/// func swift_taskGroup_initialize(group: Builtin.RawPointer)
193182
/// \endcode
194183
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
195-
void swift_taskGroup_initialize(TaskGroup *group);
184+
void swift_taskGroup_initialize(TaskGroup *group, const Metadata *T);
196185

197186
/// Attach a child task to the parent task's task group record.
198187
///
@@ -310,7 +299,8 @@ using AsyncLetWaitSignature =
310299
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
311300
void swift_asyncLet_wait(OpaqueValue *,
312301
SWIFT_ASYNC_CONTEXT AsyncContext *,
313-
AsyncLet *, Metadata *);
302+
AsyncLet *, TaskContinuationFunction *,
303+
AsyncContext *);
314304

315305
/// Wait for a potentially-throwing async-let to complete.
316306
///
@@ -324,7 +314,9 @@ void swift_asyncLet_wait(OpaqueValue *,
324314
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
325315
void swift_asyncLet_wait_throwing(OpaqueValue *,
326316
SWIFT_ASYNC_CONTEXT AsyncContext *,
327-
AsyncLet *, Metadata *);
317+
AsyncLet *,
318+
ThrowingTaskFutureWaitContinuationFunction *,
319+
AsyncContext *);
328320

329321
/// Its Swift signature is
330322
///

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1744,7 +1744,7 @@ FUNCTION(TaskGroupInitialize,
17441744
swift_taskGroup_initialize, SwiftCC,
17451745
ConcurrencyAvailability,
17461746
RETURNS(VoidTy),
1747-
ARGS(Int8PtrTy),
1747+
ARGS(Int8PtrTy, TypeMetadataPtrTy),
17481748
ATTRS(NoUnwind))
17491749

17501750
// void swift_taskGroup_destroy(TaskGroup *group);

lib/AST/Builtins.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,7 +1437,7 @@ static ValueDecl *getCreateAsyncTaskFuture(ASTContext &ctx, Identifier id) {
14371437

14381438
static ValueDecl *getCreateAsyncTaskGroupFuture(ASTContext &ctx, Identifier id) {
14391439
BuiltinFunctionBuilder builder(ctx);
1440-
auto genericParam = makeGenericParam().build(builder);
1440+
auto genericParam = makeGenericParam().build(builder); // <T>
14411441
builder.addParameter(makeConcrete(ctx.getIntType())); // flags
14421442
builder.addParameter(
14431443
makeConcrete(OptionalType::get(ctx.TheRawPointerType))); // group
@@ -1520,7 +1520,8 @@ static ValueDecl *getEndAsyncLet(ASTContext &ctx, Identifier id) {
15201520

15211521
static ValueDecl *getCreateTaskGroup(ASTContext &ctx, Identifier id) {
15221522
return getBuiltinFunction(ctx, id, _thin,
1523-
_parameters(),
1523+
_generics(_unrestricted),
1524+
_parameters(_metatype(_typeparam(0))),
15241525
_rawPointer);
15251526
}
15261527

lib/IRGen/CallEmission.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ class CallEmission {
119119

120120
return result;
121121
}
122+
123+
virtual llvm::Value *getResumeFunctionPointer() = 0;
124+
virtual llvm::Value *getAsyncContext() = 0;
122125
};
123126

124127
std::unique_ptr<CallEmission>

lib/IRGen/Callee.h

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -209,24 +209,16 @@ namespace irgen {
209209
///
210210
/// This is a micro-optimization we apply to certain special functions
211211
/// that we know don't need generics.
212-
bool suppressGenerics() const {
212+
bool useSpecialConvention() const {
213213
if (!isSpecial()) return false;
214214

215215
switch (getSpecialKind()) {
216-
case SpecialKind::TaskFutureWait:
216+
case SpecialKind::AsyncLetWaitThrowing:
217217
case SpecialKind::TaskFutureWaitThrowing:
218+
case SpecialKind::TaskFutureWait:
218219
case SpecialKind::AsyncLetWait:
219-
case SpecialKind::AsyncLetWaitThrowing:
220220
case SpecialKind::TaskGroupWaitNext:
221-
// FIXME: I have disabled this optimization, if we bring it back we
222-
// need to debug why it currently does not work (call emission
223-
// computes an undef return pointer) and change the runtime entries to
224-
// remove the extra type parameter.
225-
//
226-
// We suppress generics from these as a code-size optimization
227-
// because the runtime can recover the success type from the
228-
// future.
229-
return false;
221+
return true;
230222
}
231223
llvm_unreachable("covered switch");
232224
}
@@ -372,9 +364,7 @@ namespace irgen {
372364
return !kind.isAsyncFunctionPointer();
373365
}
374366

375-
bool suppressGenerics() const {
376-
return kind.suppressGenerics();
377-
}
367+
bool useSpecialConvention() const { return kind.useSpecialConvention(); }
378368
};
379369

380370
class Callee {
@@ -438,9 +428,7 @@ namespace irgen {
438428
return Fn.getSignature();
439429
}
440430

441-
bool suppressGenerics() const {
442-
return Fn.suppressGenerics();
443-
}
431+
bool useSpecialConvention() const { return Fn.useSpecialConvention(); }
444432

445433
/// If this callee has a value for the Swift context slot, return
446434
/// it; otherwise return non-null.
@@ -458,6 +446,7 @@ namespace irgen {
458446
llvm::Value *getObjCMethodSelector() const;
459447
};
460448

449+
FunctionPointer::Kind classifyFunctionPointerKind(SILFunction *fn);
461450
} // end namespace irgen
462451
} // end namespace swift
463452

lib/IRGen/GenBuiltin.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
250250
}
251251

252252
if (Builtin.ID == BuiltinValueKind::CreateTaskGroup) {
253-
out.add(emitCreateTaskGroup(IGF));
253+
// Claim metadata pointer.
254+
(void)args.claimAll();
255+
out.add(emitCreateTaskGroup(IGF, substitutions));
254256
return;
255257
}
256258

0 commit comments

Comments
 (0)