Skip to content

Commit 9084d4b

Browse files
authored
Merge pull request #37474 from rjmccall/merge-abi-2-into-5.5
Merge the concurrency-5.5-abi-2 branch into release/5.5
2 parents 0a18395 + dac80f6 commit 9084d4b

File tree

95 files changed

+2345
-738
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+2345
-738
lines changed

include/swift/ABI/AsyncLet.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===--- AsyncLet.h - ABI structures for async let -00-----------*- 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 task groups.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_ABI_TASK_ASYNC_LET_H
18+
#define SWIFT_ABI_TASK_ASYNC_LET_H
19+
20+
#include "swift/ABI/Task.h"
21+
#include "swift/ABI/HeapObject.h"
22+
#include "swift/Runtime/Concurrency.h"
23+
#include "swift/Runtime/Config.h"
24+
#include "swift/Basic/RelativePointer.h"
25+
#include "swift/Basic/STLExtras.h"
26+
27+
namespace swift {
28+
29+
/// Represents an in-flight `async let`, i.e. the Task that is computing the
30+
/// result of the async let, along with the awaited status and other metadata.
31+
class alignas(Alignment_AsyncLet) AsyncLet {
32+
public:
33+
// These constructors do not initialize the AsyncLet instance, and the
34+
// destructor does not destroy the AsyncLet instance; you must call
35+
// swift_asyncLet_{start,end} yourself.
36+
constexpr AsyncLet()
37+
: PrivateData{} {}
38+
39+
// FIXME: not sure how many words we should reserve
40+
void *PrivateData[NumWords_AsyncLet];
41+
42+
// TODO: we could offer a "was awaited on" check here
43+
44+
/// Returns the child task that is associated with this async let.
45+
/// The tasks completion is used to fulfil the value represented by this async let.
46+
AsyncTask *getTask() const;
47+
48+
};
49+
50+
} // end namespace swift
51+
52+
#endif // SWIFT_ABI_TASK_ASYNC_LET_H

include/swift/ABI/Executor.h

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,42 @@ class AsyncContext;
2727
class AsyncTask;
2828
class DefaultActor;
2929
class Job;
30-
31-
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
32-
SWIFT_EXPORT_FROM(swift_Concurrency)
33-
Metadata* MainActorMetadata;
30+
class SerialExecutorWitnessTable;
3431

3532
/// An unmanaged reference to an executor.
3633
///
37-
/// The representation is two words: identity and implementation.
38-
/// The identity word is a reference to the executor object; for
39-
/// default actors, this is the actor object. The implementation
40-
/// word describes how the executor works; it carries a witness table
41-
/// as well as a small number of bits indicating various special
42-
/// implementation properties. As an exception to both of these
43-
/// rules, a null identity represents a generic executor and
44-
/// implies a null implementation word.
34+
/// This type corresponds to the type Optional<Builtin.Executor> in
35+
/// Swift. The representation of nil in Optional<Builtin.Executor>
36+
/// aligns with what this type calls the generic executor, so the
37+
/// notional subtype of this type which is never generic corresponds
38+
/// to the type Builtin.Executor.
39+
///
40+
/// An executor reference is divided into two pieces:
41+
///
42+
/// - The identity, which is just a (potentially ObjC) object
43+
/// reference; when this is null, the reference is generic.
44+
/// Equality of executor references is based solely on equality
45+
/// of identity.
46+
///
47+
/// - The implementation, which is an optional reference to a
48+
/// witness table for the SerialExecutor protocol. When this
49+
/// is null, but the identity is non-null, the reference is to
50+
/// a default actor. The low bits of the implementation pointer
51+
/// are reserved for the use of marking interesting properties
52+
/// about the executor's implementation. The runtime masks these
53+
/// bits off before accessing the witness table, so setting them
54+
/// in the future should back-deploy as long as the witness table
55+
/// reference is still present.
4556
class ExecutorRef {
4657
HeapObject *Identity; // Not necessarily Swift reference-countable
4758
uintptr_t Implementation;
4859

60+
// We future-proof the ABI here by masking the low bits off the
61+
// implementation pointer before using it as a witness table.
62+
enum: uintptr_t {
63+
WitnessTableMask = ~uintptr_t(alignof(void*) - 1)
64+
};
65+
4966
constexpr ExecutorRef(HeapObject *identity, uintptr_t implementation)
5067
: Identity(identity), Implementation(implementation) {}
5168

@@ -58,23 +75,11 @@ class ExecutorRef {
5875
return ExecutorRef(nullptr, 0);
5976
}
6077

61-
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
62-
/// NOTE: I didn't go with Executor::forMainActor(DefaultActor*) because
63-
/// __swift_run_job_main_executor can't take more than one argument.
64-
static ExecutorRef mainExecutor() {
65-
auto identity = getMainActorIdentity();
66-
return ExecutorRef(identity, 0);
67-
}
68-
static HeapObject *getMainActorIdentity() {
69-
return reinterpret_cast<HeapObject*>(
70-
ExecutorRefFlags::MainActorIdentity);
71-
}
72-
7378
/// Given a pointer to a default actor, return an executor reference
7479
/// for it.
7580
static ExecutorRef forDefaultActor(DefaultActor *actor) {
7681
assert(actor);
77-
return ExecutorRef(actor, unsigned(ExecutorRefFlags::DefaultActor));
82+
return ExecutorRef(actor, 0);
7883
}
7984

8085
HeapObject *getIdentity() const {
@@ -86,37 +91,29 @@ class ExecutorRef {
8691
return Identity == 0;
8792
}
8893

89-
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
90-
bool isMainExecutor() const {
91-
if (Identity == getMainActorIdentity())
92-
return true;
93-
94-
if (Identity == nullptr || MainActorMetadata == nullptr)
95-
return false;
96-
97-
Metadata const* metadata = swift_getObjectType(Identity);
98-
return metadata == MainActorMetadata;
99-
}
100-
10194
/// Is this a default-actor executor reference?
10295
bool isDefaultActor() const {
103-
return Implementation & unsigned(ExecutorRefFlags::DefaultActor);
96+
return !isGeneric() && Implementation == 0;
10497
}
10598
DefaultActor *getDefaultActor() const {
10699
assert(isDefaultActor());
107100
return reinterpret_cast<DefaultActor*>(Identity);
108101
}
109102

103+
const SerialExecutorWitnessTable *getSerialExecutorWitnessTable() const {
104+
assert(!isGeneric() && !isDefaultActor());
105+
auto table = Implementation & WitnessTableMask;
106+
return reinterpret_cast<const SerialExecutorWitnessTable*>(table);
107+
}
108+
110109
/// Do we have to do any work to start running as the requested
111110
/// executor?
112111
bool mustSwitchToRun(ExecutorRef newExecutor) const {
113112
return Identity != newExecutor.Identity;
114113
}
115114

116115
bool operator==(ExecutorRef other) const {
117-
return Identity == other.Identity
118-
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
119-
|| (isMainExecutor() && other.isMainExecutor());
116+
return Identity == other.Identity;
120117
}
121118
bool operator!=(ExecutorRef other) const {
122119
return !(*this == other);

include/swift/ABI/MetadataValues.h

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ enum {
4949

5050
/// The number of words in a task group.
5151
NumWords_TaskGroup = 32,
52+
53+
/// The number of words in an AsyncLet (flags + task pointer)
54+
NumWords_AsyncLet = 8, // TODO: not sure how much is enough, these likely could be pretty small
5255
};
5356

5457
struct InProcess;
@@ -127,6 +130,9 @@ const size_t Alignment_DefaultActor = MaximumAlignment;
127130
/// The alignment of a TaskGroup.
128131
const size_t Alignment_TaskGroup = MaximumAlignment;
129132

133+
/// The alignment of an AsyncLet.
134+
const size_t Alignment_AsyncLet = MaximumAlignment;
135+
130136
/// Flags stored in the value-witness table.
131137
template <typename int_type>
132138
class TargetValueWitnessFlags {
@@ -1994,7 +2000,7 @@ enum class JobPriority : size_t {
19942000
};
19952001

19962002
/// Flags for schedulable jobs.
1997-
class JobFlags : public FlagSet<size_t> {
2003+
class JobFlags : public FlagSet<uint32_t> {
19982004
public:
19992005
enum {
20002006
Kind = 0,
@@ -2013,7 +2019,7 @@ class JobFlags : public FlagSet<size_t> {
20132019
Task_IsContinuingAsyncTask = 27,
20142020
};
20152021

2016-
explicit JobFlags(size_t bits) : FlagSet(bits) {}
2022+
explicit JobFlags(uint32_t bits) : FlagSet(bits) {}
20172023
JobFlags(JobKind kind) { setKind(kind); }
20182024
JobFlags(JobKind kind, JobPriority priority) {
20192025
setKind(kind);
@@ -2194,20 +2200,6 @@ enum class ContinuationStatus : size_t {
21942200
Resumed = 2
21952201
};
21962202

2197-
/// Flags describing the executor implementation that are stored
2198-
/// in the ExecutorRef.
2199-
enum class ExecutorRefFlags : size_t {
2200-
// The number of bits available here is very limited because it's
2201-
// potentially just the alignment bits of a protocol witness table
2202-
// pointer
2203-
2204-
/// The executor is a default actor.
2205-
DefaultActor = 0x1,
2206-
2207-
/// TODO: remove this
2208-
MainActorIdentity = 0x2,
2209-
};
2210-
22112203
} // end namespace swift
22122204

22132205
#endif // SWIFT_ABI_METADATAVALUES_H

include/swift/ABI/Task.h

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ class TaskGroup;
3939
extern FullMetadata<DispatchClassMetadata> jobHeapMetadata;
4040

4141
/// A schedulable job.
42-
class alignas(2 * alignof(void*)) Job : public HeapObject {
42+
class alignas(2 * alignof(void*)) Job :
43+
// For async-let tasks, the refcount bits are initialized as "immortal"
44+
// because such a task is allocated with the parent's stack allocator.
45+
public HeapObject {
4346
public:
4447
// Indices into SchedulerPrivate, for use by the runtime.
4548
enum {
@@ -65,6 +68,9 @@ class alignas(2 * alignof(void*)) Job : public HeapObject {
6568

6669
JobFlags Flags;
6770

71+
// Derived classes can use this to store a Job Id.
72+
uint32_t Id = 0;
73+
6874
// We use this union to avoid having to do a second indirect branch
6975
// when resuming an asynchronous task, which we expect will be the
7076
// common case.
@@ -88,6 +94,14 @@ class alignas(2 * alignof(void*)) Job : public HeapObject {
8894
assert(isAsyncTask() && "wrong constructor for a non-task job");
8995
}
9096

97+
/// Create a job with "immortal" reference counts.
98+
/// Used for async let tasks.
99+
Job(JobFlags flags, TaskContinuationFunction *invoke,
100+
const HeapMetadata *metadata, InlineRefCounts::Immortal_t immortal)
101+
: HeapObject(metadata, immortal), Flags(flags), ResumeTask(invoke) {
102+
assert(isAsyncTask() && "wrong constructor for a non-task job");
103+
}
104+
91105
bool isAsyncTask() const {
92106
return Flags.isAsyncTask();
93107
}
@@ -112,8 +126,13 @@ class alignas(2 * alignof(void*)) Job : public HeapObject {
112126
};
113127

114128
// The compiler will eventually assume these.
129+
#if defined(__LP64__) || defined(_WIN64)
115130
static_assert(sizeof(Job) == 6 * sizeof(void*),
116131
"Job size is wrong");
132+
#else
133+
static_assert(sizeof(Job) == 8 * sizeof(void*),
134+
"Job size is wrong");
135+
#endif
117136
static_assert(alignof(Job) == 2 * alignof(void*),
118137
"Job alignment is wrong");
119138

@@ -220,8 +239,25 @@ class AsyncTask : public Job {
220239
Status(ActiveTaskStatus()),
221240
Local(TaskLocal::Storage()) {
222241
assert(flags.isAsyncTask());
242+
Id = getNextTaskId();
243+
}
244+
245+
/// Create a task with "immortal" reference counts.
246+
/// Used for async let tasks.
247+
AsyncTask(const HeapMetadata *metadata, InlineRefCounts::Immortal_t immortal,
248+
JobFlags flags,
249+
TaskContinuationFunction *run,
250+
AsyncContext *initialContext)
251+
: Job(flags, run, metadata, immortal),
252+
ResumeContext(initialContext),
253+
Status(ActiveTaskStatus()),
254+
Local(TaskLocal::Storage()) {
255+
assert(flags.isAsyncTask());
256+
Id = getNextTaskId();
223257
}
224258

259+
~AsyncTask();
260+
225261
/// Given that we've already fully established the job context
226262
/// in the current thread, start running this task. To establish
227263
/// the job context correctly, call swift_job_run or
@@ -481,13 +517,24 @@ class AsyncTask : public Job {
481517
return reinterpret_cast<AsyncTask *&>(
482518
SchedulerPrivate[NextWaitingTaskIndex]);
483519
}
520+
521+
/// Get the next non-zero Task ID.
522+
uint32_t getNextTaskId() {
523+
static std::atomic<uint32_t> Id(1);
524+
uint32_t Next = Id.fetch_add(1, std::memory_order_relaxed);
525+
if (Next == 0) Next = Id.fetch_add(1, std::memory_order_relaxed);
526+
return Next;
527+
}
484528
};
485529

486530
// The compiler will eventually assume these.
487531
static_assert(sizeof(AsyncTask) == 14 * sizeof(void*),
488532
"AsyncTask size is wrong");
489533
static_assert(alignof(AsyncTask) == 2 * alignof(void*),
490534
"AsyncTask alignment is wrong");
535+
// Libc hardcodes this offset to extract the TaskID
536+
static_assert(offsetof(AsyncTask, Id) == 4 * sizeof(void *) + 4,
537+
"AsyncTask::Id offset is wrong");
491538

492539
SWIFT_CC(swiftasync)
493540
inline void Job::runInFullyEstablishedContext() {
@@ -608,13 +655,13 @@ class FutureAsyncContext : public AsyncContext {
608655
/// This matches the ABI of a closure `() async throws -> ()`
609656
using AsyncVoidClosureEntryPoint =
610657
SWIFT_CC(swiftasync)
611-
void (SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT HeapObject *);
658+
void (SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT void *);
612659

613660
/// This matches the ABI of a closure `<T>() async throws -> T`
614661
using AsyncGenericClosureEntryPoint =
615662
SWIFT_CC(swiftasync)
616663
void(OpaqueValue *,
617-
SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT HeapObject *);
664+
SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT void *);
618665

619666
/// This matches the ABI of the resume function of a closure
620667
/// `() async throws -> ()`.
@@ -628,7 +675,7 @@ class AsyncContextPrefix {
628675
// passing the closure context instead of via the async context)
629676
AsyncVoidClosureEntryPoint *__ptrauth_swift_task_resume_function
630677
asyncEntryPoint;
631-
HeapObject *closureContext;
678+
void *closureContext;
632679
SwiftError *errorResult;
633680
};
634681

@@ -641,7 +688,7 @@ class FutureAsyncContextPrefix {
641688
// passing the closure context instead of via the async context)
642689
AsyncGenericClosureEntryPoint *__ptrauth_swift_task_resume_function
643690
asyncEntryPoint;
644-
HeapObject *closureContext;
691+
void *closureContext;
645692
SwiftError *errorResult;
646693
};
647694

include/swift/ABI/TaskGroup.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ namespace swift {
2929
/// The task group is responsible for maintaining dynamically created child tasks.
3030
class alignas(Alignment_TaskGroup) TaskGroup {
3131
public:
32-
// These constructors do not initialize the actor instance, and the
33-
// destructor does not destroy the actor instance; you must call
32+
// These constructors do not initialize the group instance, and the
33+
// destructor does not destroy the group instance; you must call
3434
// swift_taskGroup_{initialize,destroy} yourself.
3535
constexpr TaskGroup()
3636
: PrivateData{} {}
@@ -43,4 +43,4 @@ class alignas(Alignment_TaskGroup) TaskGroup {
4343

4444
} // end namespace swift
4545

46-
#endif
46+
#endif // SWIFT_ABI_TASK_GROUP_H

0 commit comments

Comments
 (0)