Skip to content

Commit dd8cbe3

Browse files
committed
[CoroutineAccessors] Use retcon.once variant.
Allocate a coroutine frame in the caller based on the size in the corresponding "function pointer" and pass it along with an allocator to the callee.
1 parent 3d655f5 commit dd8cbe3

34 files changed

+1049
-140
lines changed

include/swift/ABI/Coro.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===---------- Coro.h - ABI structures for coroutines ----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Swift ABI describing the coroutine ABI.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_ABI_CORO_H
18+
#define SWIFT_ABI_CORO_H
19+
20+
#include "swift/Basic/FlagSet.h"
21+
#include <cstddef>
22+
#include <cstdint>
23+
24+
namespace swift {
25+
26+
enum class CoroAllocatorKind : uint8_t {
27+
// stacksave/stackrestore
28+
Sync = 0,
29+
// swift_task_alloc/swift_task_dealloc_through
30+
Async = 1,
31+
// malloc/free
32+
Malloc = 2,
33+
};
34+
35+
class CoroAllocatorFlags : public FlagSet<uint32_t> {
36+
public:
37+
// clang-format off
38+
enum {
39+
Kind = 0,
40+
Kind_width = 8,
41+
42+
// 24 reserved bits
43+
};
44+
// clang-format on
45+
46+
constexpr explicit CoroAllocatorFlags(uint32_t bits) : FlagSet(bits) {}
47+
CoroAllocatorFlags(CoroAllocatorKind kind) { setKind(kind); }
48+
constexpr CoroAllocatorFlags() {}
49+
50+
FLAGSET_DEFINE_FIELD_ACCESSORS(Kind, Kind_width, CoroAllocatorKind, getKind,
51+
setKind)
52+
};
53+
54+
using CoroAllocation = void *;
55+
using CoroAllocateFn = CoroAllocation (*)(size_t);
56+
using CoroDealllocateFn = void (*)(CoroAllocation);
57+
58+
struct CoroAllocator {
59+
CoroAllocatorFlags flags;
60+
CoroAllocateFn allocate;
61+
CoroDealllocateFn deallocate;
62+
63+
/// Whether the allocator should deallocate memory on calls to
64+
/// swift_coro_dealloc.
65+
constexpr bool shouldDeallocateImmediately() {
66+
// Only the "mallocator" should immediately deallocate in
67+
// swift_coro_dealloc. It must because the ABI does not provide a means for
68+
// the callee to return its allocations to the caller.
69+
//
70+
// Async allocations can be deferred until the first non-coroutine caller
71+
// from where swift_task_dealloc_through can be called and passed the
72+
// caller-allocated fixed-per-callee-sized-frame.
73+
// Stack allocations just pop the stack.
74+
return flags.getKind() == CoroAllocatorKind::Malloc;
75+
}
76+
};
77+
78+
} // end namespace swift
79+
80+
#endif

include/swift/AST/IRGenOptions.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ class IRGenOptions {
386386
unsigned LazyInitializeClassMetadata : 1;
387387
unsigned LazyInitializeProtocolConformances : 1;
388388
unsigned IndirectAsyncFunctionPointer : 1;
389+
unsigned IndirectCoroFunctionPointer : 1;
389390

390391
/// Use absolute function references instead of relative ones.
391392
/// Mainly used on WebAssembly, that doesn't support relative references
@@ -580,10 +581,10 @@ class IRGenOptions {
580581
HasValueNamesSetting(false), ValueNames(false),
581582
ReflectionMetadata(ReflectionMetadataMode::Runtime),
582583
EnableReflectionNames(true), DisableLLVMMergeFunctions(false),
583-
EnableAnonymousContextMangledNames(false),
584-
ForcePublicLinkage(false), LazyInitializeClassMetadata(false),
584+
EnableAnonymousContextMangledNames(false), ForcePublicLinkage(false),
585+
LazyInitializeClassMetadata(false),
585586
LazyInitializeProtocolConformances(false),
586-
IndirectAsyncFunctionPointer(false),
587+
IndirectAsyncFunctionPointer(false), IndirectCoroFunctionPointer(false),
587588
CompactAbsoluteFunctionPointer(false), DisableLegacyTypeInfo(false),
588589
PrespecializeGenericMetadata(false), UseIncrementalLLVMCodeGen(true),
589590
UseTypeLayoutValueHandling(true), ForceStructTypeLayouts(false),
@@ -598,16 +599,15 @@ class IRGenOptions {
598599
EnableGlobalISel(false), VirtualFunctionElimination(false),
599600
WitnessMethodElimination(false), ConditionalRuntimeRecords(false),
600601
InternalizeAtLink(false), InternalizeSymbols(false),
601-
MergeableSymbols(false),
602-
EmitGenericRODatas(true), NoPreallocatedInstantiationCaches(false),
602+
MergeableSymbols(false), EmitGenericRODatas(true),
603+
NoPreallocatedInstantiationCaches(false),
603604
DisableReadonlyStaticObjects(false), CollocatedMetadataFunctions(false),
604605
ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false),
605606
UseFragileResilientProtocolWitnesses(false), EnableHotColdSplit(false),
606607
EmitAsyncFramePushPopMetadata(true), EmitTypeMallocForCoroFrame(false),
607608
EmitYieldOnce2AsYieldOnce(true), AsyncFramePointerAll(false),
608-
UseProfilingMarkerThunks(false),
609-
DebugInfoForProfiling(false), CmdArgs(),
610-
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
609+
UseProfilingMarkerThunks(false), DebugInfoForProfiling(false),
610+
CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()),
611611
TypeInfoFilter(TypeInfoDumpFilter::All),
612612
PlatformCCallingConvention(llvm::CallingConv::C), UseCASBackend(false),
613613
CASObjMode(llvm::CASBackendMode::Native) {

include/swift/IRGen/Linking.h

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,11 @@ class LinkEntity {
389389
/// The pointer is an AbstractFunctionDecl*.
390390
AsyncFunctionPointerAST,
391391

392+
/// The same as CoroFunctionPointer but with a different stored value, for
393+
/// use by TBDGen.
394+
/// The pointer is an AbstractFunctionDecl*.
395+
CoroFunctionPointerAST,
396+
392397
/// The pointer is a SILFunction*.
393398
DynamicallyReplaceableFunctionKey,
394399

@@ -558,11 +563,6 @@ class LinkEntity {
558563
/// The pointer is a SILFunction*.
559564
CoroFunctionPointer,
560565

561-
/// The same as CoroFunctionPointer but with a different stored value, for
562-
/// use by TBDGen.
563-
/// The pointer is an AbstractFunctionDecl*.
564-
CoroFunctionPointerAST,
565-
566566
/// An coro function pointer for a method dispatch thunk. The pointer is
567567
/// a FuncDecl* inside a protocol or a class.
568568
DispatchThunkCoroFunctionPointer,
@@ -610,9 +610,7 @@ class LinkEntity {
610610
return !(LHS == RHS);
611611
}
612612

613-
static bool isDeclKind(Kind k) {
614-
return k <= Kind::AsyncFunctionPointerAST;
615-
}
613+
static bool isDeclKind(Kind k) { return k <= Kind::CoroFunctionPointerAST; }
616614
static bool isTypeKind(Kind k) {
617615
return k >= Kind::ProtocolWitnessTableLazyAccessFunction;
618616
}
@@ -1544,6 +1542,17 @@ class LinkEntity {
15441542
return entity;
15451543
}
15461544

1545+
static LinkEntity forCoroFunctionPointer(SILDeclRef declRef) {
1546+
LinkEntity entity;
1547+
entity.setForDecl(declRef.isDistributedThunk()
1548+
? Kind::DistributedThunkCoroFunctionPointer
1549+
: Kind::CoroFunctionPointerAST,
1550+
declRef.getAbstractFunctionDecl());
1551+
entity.SecondaryPointer =
1552+
reinterpret_cast<void *>(static_cast<uintptr_t>(declRef.kind));
1553+
return entity;
1554+
}
1555+
15471556
LinkEntity getUnderlyingEntityForCoroFunctionPointer() const {
15481557
LinkEntity entity;
15491558
entity.Pointer = Pointer;

include/swift/Runtime/Concurrency.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SWIFT_RUNTIME_CONCURRENCY_H
1919

2020
#include "swift/ABI/AsyncLet.h"
21+
#include "swift/ABI/Coro.h"
2122
#include "swift/ABI/Task.h"
2223
#include "swift/ABI/TaskGroup.h"
2324

@@ -119,6 +120,35 @@ void *swift_task_alloc(size_t size);
119120
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
120121
void swift_task_dealloc(void *ptr);
121122

123+
/// Deallocate multiple memory allocations in a task.
124+
///
125+
/// The pointer provided must be a pointer previously allocated on
126+
/// this task that has not yet been deallocated. All allocations up to and
127+
/// including that allocation will be deallocated.
128+
SWIFT_EXPORT_FROM(swift_Concurrency)
129+
SWIFT_CC(swift) void swift_task_dealloc_through(void *ptr);
130+
131+
// TODO: CoroutineAccessors: Eliminate this entry point and replace its uses
132+
// with direct references the globals.
133+
SWIFT_EXPORT_FROM(swift_Concurrency)
134+
SWIFT_CC(swift)
135+
CoroAllocator *swift_coro_getGlobalAllocator(CoroAllocatorFlags flags);
136+
137+
// TODO: CoroutineAccessors: Mark the underlying struct const.
138+
SWIFT_EXPORT_FROM(swift_Concurrency)
139+
CoroAllocator *const _swift_coro_task_allocator;
140+
141+
// TODO: CoroutineAccessors: Move these declarations back to swiftCore {{
142+
SWIFT_EXPORT_FROM(swift_Concurrency)
143+
SWIFT_CC(swift) void *swift_coro_alloc(CoroAllocator *allocator, size_t size);
144+
SWIFT_EXPORT_FROM(swift_Concurrency)
145+
SWIFT_CC(swift) void swift_coro_dealloc(CoroAllocator *allocator, void *ptr);
146+
147+
// TODO: CoroutineAccessors: Mark the underlying struct const.
148+
SWIFT_EXPORT_FROM(swift_Concurrency)
149+
CoroAllocator *const _swift_coro_malloc_allocator;
150+
// }} TODO: CoroutineAccessors
151+
122152
/// Cancel a task and all of its child tasks.
123153
///
124154
/// This can be called from any thread.

include/swift/Runtime/Coro.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//===-------- Coro.h - Runtime interface for coroutines ---------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// The runtime interface for coroutines.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_RUNTIME_CORO_H
18+
#define SWIFT_RUNTIME_CORO_H
19+
20+
#include "swift/ABI/Coro.h"
21+
#include "swift/Runtime/Config.h"
22+
#include <cstddef>
23+
24+
namespace swift {} // end namespace swift
25+
26+
#endif

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2325,6 +2325,16 @@ FUNCTION(TaskDealloc,
23252325
EFFECT(Concurrency),
23262326
MEMEFFECTS(ArgMemOnly))
23272327

2328+
// void swift_task_dealloc_through(void *ptr);
2329+
FUNCTION(TaskDeallocThrough,
2330+
_Concurrency, swift_task_dealloc_through, SwiftCC,
2331+
CoroutineAccessorsAvailability,
2332+
RETURNS(VoidTy),
2333+
ARGS(Int8PtrTy),
2334+
ATTRS(NoUnwind),
2335+
EFFECT(Concurrency),
2336+
MEMEFFECTS(ArgMemOnly))
2337+
23282338
// void swift_task_cancel(AsyncTask *task);
23292339
FUNCTION(TaskCancel,
23302340
_Concurrency, swift_task_cancel, SwiftCC,
@@ -2989,6 +2999,36 @@ FUNCTION(MemsetS, c, memset_s, C_CC, AlwaysAvailable,
29892999
EFFECT(NoEffect),
29903000
UNKNOWN_MEMEFFECTS)
29913001

3002+
// void *swift_coro_alloc(CoroAllocator *, size_t size);
3003+
FUNCTION(CoroAlloc,
3004+
_Concurrency, swift_coro_alloc, SwiftCC,
3005+
CoroutineAccessorsAvailability,
3006+
RETURNS(Int8PtrTy),
3007+
ARGS(CoroAllocatorPtrTy, SizeTy),
3008+
NO_ATTRS,
3009+
EFFECT(Allocating, Concurrency),
3010+
UNKNOWN_MEMEFFECTS)
3011+
3012+
// void swift_coro_dealloc(CoroAllocator *, void *ptr);
3013+
FUNCTION(CoroDealloc,
3014+
_Concurrency, swift_coro_dealloc, SwiftCC,
3015+
CoroutineAccessorsAvailability,
3016+
RETURNS(VoidTy),
3017+
ARGS(CoroAllocatorPtrTy, Int8PtrTy),
3018+
NO_ATTRS,
3019+
EFFECT(Deallocating, Concurrency),
3020+
UNKNOWN_MEMEFFECTS)
3021+
3022+
// const CoroAllocator *swift_coro_getGlobalAllocator(CoroAllocatorFlags flags);
3023+
FUNCTION(CoroGetGlobalAllocator,
3024+
_Concurrency, swift_coro_getGlobalAllocator, SwiftCC,
3025+
CoroutineAccessorsAvailability,
3026+
RETURNS(CoroAllocatorPtrTy),
3027+
ARGS(CoroAllocatorFlagsTy),
3028+
ATTRS(NoUnwind, WillReturn),
3029+
EFFECT(Allocating),
3030+
UNKNOWN_MEMEFFECTS)
3031+
29923032
#undef RETURNS
29933033
#undef ARGS
29943034
#undef ATTRS

include/swift/SIL/SILFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,10 @@ class SILFunction
768768

769769
bool isAsync() const { return LoweredType->isAsync(); }
770770

771+
bool isCalleeAllocatedCoroutine() const {
772+
return LoweredType->isCalleeAllocatedCoroutine();
773+
}
774+
771775
/// Returns the calling convention used by this entry point.
772776
SILFunctionTypeRepresentation getRepresentation() const {
773777
return getLoweredFunctionType()->getRepresentation();

include/swift/SIL/SILSymbolVisitor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class SILSymbolVisitor {
100100
virtual void addAsyncFunctionPointer(SILDeclRef declRef) {}
101101
virtual void addBaseConformanceDescriptor(BaseConformance BC) {}
102102
virtual void addClassMetadataBaseOffset(ClassDecl *CD) {}
103+
virtual void addCoroFunctionPointer(SILDeclRef declRef) {}
103104
virtual void addDispatchThunk(SILDeclRef declRef) {}
104105
virtual void addDynamicFunction(AbstractFunctionDecl *AFD,
105106
DynamicKind dynKind) {}

lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3431,6 +3431,11 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
34313431
// AsyncFunctionPointer access.
34323432
Opts.IndirectAsyncFunctionPointer = Triple.isOSBinFormatCOFF();
34333433

3434+
// PE/COFF cannot deal with the cross-module reference to the
3435+
// CoroFunctionPointer data block. Force the use of indirect
3436+
// CoroFunctionPointer access.
3437+
Opts.IndirectCoroFunctionPointer = Triple.isOSBinFormatCOFF();
3438+
34343439
// On some Harvard architectures that allow sliding code and data address space
34353440
// offsets independently, it's impossible to make direct relative reference to
34363441
// code from data because the relative offset between them is not representable.

lib/IRGen/CallEmission.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ class CallEmission {
7272
/// Whether this is a coroutine invocation.
7373
bool IsCoroutine;
7474

75+
/// Whether this is a invocation for a coroutine that dynamically allocates
76+
/// in the callee.
77+
bool IsCalleeAllocatedCoroutine;
78+
7579
/// Whether we've emitted the call for the current callee yet. This
7680
/// is just for debugging purposes --- e.g. the destructor asserts
7781
/// that it's true --- but is otherwise derivable from
@@ -178,6 +182,9 @@ class CallEmission {
178182
virtual llvm::Value *getResumeFunctionPointer() = 0;
179183
virtual llvm::Value *getAsyncContext() = 0;
180184

185+
virtual StackAddress getCoroStaticFrame() = 0;
186+
virtual llvm::Value *getCoroAllocator() = 0;
187+
181188
void setIndirectTypedErrorResultSlot(llvm::Value *addr) {
182189
Args[IndirectTypedErrorArgIdx] = addr;
183190
}

0 commit comments

Comments
 (0)