Skip to content

Commit 0555a86

Browse files
committed
Extract executor stuff out into a separate header and
start introducing the idea of a swiftasync CC.
1 parent 46f53a0 commit 0555a86

File tree

5 files changed

+131
-58
lines changed

5 files changed

+131
-58
lines changed

include/swift/ABI/Executor.h

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//===--- Executor.h - ABI structures for executors --------------*- 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 executors.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_ABI_EXECUTOR_H
18+
#define SWIFT_ABI_EXECUTOR_H
19+
20+
#include <inttypes.h>
21+
22+
namespace swift {
23+
class AsyncContext;
24+
class AsyncTask;
25+
class DefaultActor;
26+
class Job;
27+
28+
/// An ExecutorRef isn't necessarily just a pointer to an executor
29+
/// object; it may have other bits set.
30+
class ExecutorRef {
31+
static constexpr uintptr_t IsDefaultActor = 1;
32+
static constexpr uintptr_t PointerMask = 7;
33+
34+
uintptr_t Value;
35+
36+
constexpr ExecutorRef(uintptr_t value) : Value(value) {}
37+
38+
public:
39+
/// A generic execution environment. When running in a generic
40+
/// environment, it's presumed to be okay to switch synchronously
41+
/// to an actor. As an executor request, this represents a request
42+
/// to drop whatever the current actor is.
43+
constexpr static ExecutorRef generic() {
44+
return ExecutorRef(0);
45+
}
46+
47+
/// Given a pointer to a default actor, return an executor reference
48+
/// for it.
49+
static ExecutorRef forDefaultActor(DefaultActor *actor) {
50+
assert(actor);
51+
return ExecutorRef(reinterpret_cast<uintptr_t>(actor) | IsDefaultActor);
52+
}
53+
54+
/// Is this the generic executor reference?
55+
bool isGeneric() const {
56+
return Value == 0;
57+
}
58+
59+
/// Is this a default-actor executor reference?
60+
bool isDefaultActor() const {
61+
return Value & IsDefaultActor;
62+
}
63+
DefaultActor *getDefaultActor() const {
64+
assert(isDefaultActor());
65+
return reinterpret_cast<DefaultActor*>(Value & ~PointerMask);
66+
}
67+
68+
/// Do we have to do any work to start running as the requested
69+
/// executor?
70+
bool mustSwitchToRun(ExecutorRef newExecutor) const {
71+
return *this != newExecutor;
72+
}
73+
74+
bool operator==(ExecutorRef other) const {
75+
return Value == other.Value;
76+
}
77+
bool operator!=(ExecutorRef other) const {
78+
return Value != other.Value;
79+
}
80+
};
81+
82+
using JobInvokeFunction =
83+
SWIFT_CC(swiftasync)
84+
void (Job *, ExecutorRef);
85+
86+
using TaskContinuationFunction =
87+
SWIFT_CC(swiftasync)
88+
void (AsyncTask *, ExecutorRef, AsyncContext *);
89+
90+
template <class Fn>
91+
struct AsyncFunctionTypeImpl;
92+
template <class Result, class... Params>
93+
struct AsyncFunctionTypeImpl<Result(Params...)> {
94+
// TODO: expand and include the arguments in the parameters.
95+
using type = TaskContinuationFunction;
96+
};
97+
98+
template <class Fn>
99+
using AsyncFunctionType = typename AsyncFunctionTypeImpl<Fn>::type;
100+
101+
/// A "function pointer" for an async function.
102+
///
103+
/// Eventually, this will always be signed with the data key
104+
/// using a type-specific discriminator.
105+
template <class FnType>
106+
class AsyncFunctionPointer {
107+
public:
108+
/// The function to run.
109+
RelativeDirectPointer<AsyncFunctionType<FnType>,
110+
/*nullable*/ false,
111+
int32_t> Function;
112+
113+
/// The expected size of the context.
114+
uint32_t ExpectedContextSize;
115+
};
116+
117+
}
118+
119+
#endif

include/swift/ABI/Task.h

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -18,75 +18,21 @@
1818
#define SWIFT_ABI_TASK_H
1919

2020
#include "swift/Basic/RelativePointer.h"
21+
#include "swift/ABI/Executor.h"
2122
#include "swift/ABI/HeapObject.h"
2223
#include "swift/ABI/Metadata.h"
2324
#include "swift/ABI/MetadataValues.h"
2425
#include "swift/Runtime/Config.h"
2526
#include "swift/Basic/STLExtras.h"
2627

2728
namespace swift {
28-
2929
class AsyncTask;
3030
class AsyncContext;
31-
class Executor;
3231
class Job;
3332
struct OpaqueValue;
3433
struct SwiftError;
3534
class TaskStatusRecord;
3635

37-
/// An ExecutorRef isn't necessarily just a pointer to an executor
38-
/// object; it may have other bits set.
39-
struct ExecutorRef {
40-
Executor *Pointer;
41-
42-
/// Get an executor ref that represents a lack of preference about
43-
/// where execution resumes. This is only valid in continuations,
44-
/// return contexts, and so on; it is not generally passed to
45-
/// executing functions.
46-
static ExecutorRef noPreference() {
47-
return { nullptr };
48-
}
49-
50-
bool operator==(ExecutorRef other) const {
51-
return Pointer == other.Pointer;
52-
}
53-
};
54-
55-
using JobInvokeFunction =
56-
SWIFT_CC(swift)
57-
void (Job *, ExecutorRef);
58-
59-
using TaskContinuationFunction =
60-
SWIFT_CC(swift)
61-
void (AsyncTask *, ExecutorRef, AsyncContext *);
62-
63-
template <class Fn>
64-
struct AsyncFunctionTypeImpl;
65-
template <class Result, class... Params>
66-
struct AsyncFunctionTypeImpl<Result(Params...)> {
67-
// TODO: expand and include the arguments in the parameters.
68-
using type = TaskContinuationFunction;
69-
};
70-
71-
template <class Fn>
72-
using AsyncFunctionType = typename AsyncFunctionTypeImpl<Fn>::type;
73-
74-
/// A "function pointer" for an async function.
75-
///
76-
/// Eventually, this will always be signed with the data key
77-
/// using a type-specific discriminator.
78-
template <class FnType>
79-
class AsyncFunctionPointer {
80-
public:
81-
/// The function to run.
82-
RelativeDirectPointer<AsyncFunctionType<FnType>,
83-
/*nullable*/ false,
84-
int32_t> Function;
85-
86-
/// The expected size of the context.
87-
uint32_t ExpectedContextSize;
88-
};
89-
9036
/// A schedulable job.
9137
class alignas(2 * alignof(void*)) Job {
9238
protected:

include/swift/Runtime/Config.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,14 @@ extern uintptr_t __COMPATIBILITY_LIBRARIES_CANNOT_CHECK_THE_IS_SWIFT_BIT_DIRECTL
176176
#define SWIFT_INDIRECT_RESULT
177177
#endif
178178

179+
// SWIFT_CC(swiftasync) is the Swift async calling convention.
180+
// We assume that it supports mandatory tail call elimination.
181+
#if __has_attribute(swiftasynccall)
182+
#define SWIFT_CC_swiftasync __attribute__((swiftasynccall))
183+
#else
184+
#define SWIFT_CC_swiftasync SWIFT_CC_swift
185+
#endif
186+
179187
// SWIFT_CC(PreserveMost) is used in the runtime implementation to prevent
180188
// register spills on the hot path.
181189
// It is not safe to use for external calls; the loader's lazy function

stdlib/public/Concurrency/Task.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ AsyncTaskAndContext swift::swift_task_create_future_f(
303303
// be is the final hop. Store a signed null instead.
304304
initialContext->Parent = nullptr;
305305
initialContext->ResumeParent = &completeTask;
306-
initialContext->ResumeParentExecutor = ExecutorRef::noPreference();
306+
initialContext->ResumeParentExecutor = ExecutorRef::generic();
307307
initialContext->Flags = AsyncContextKind::Ordinary;
308308
initialContext->Flags.setShouldNotDeallocateInCallee(true);
309309

@@ -349,7 +349,7 @@ void swift::swift_task_future_wait(
349349

350350
// TODO: Remove this hack.
351351
void swift::swift_task_run(AsyncTask *taskToRun) {
352-
taskToRun->run(ExecutorRef::noPreference());
352+
taskToRun->run(ExecutorRef::generic());
353353
}
354354

355355
JobFlags swift::swift_task_getJobFlags(AsyncTask *task) {

unittests/runtime/TaskStatus.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ static void withSimpleTask(T &&value,
8080
}
8181

8282
static ExecutorRef createFakeExecutor(uintptr_t value) {
83-
return {reinterpret_cast<Executor*>(value)};
83+
return ExecutorRef::forDefaultActor(reinterpret_cast<DefaultActor*>(value));
8484
}
8585

8686
} // end anonymous namespace

0 commit comments

Comments
 (0)