blob: b1dc62a586bc5b3de59f71fa59645b5d3c1e0bbe [file] [log] [blame]
//===--- Executor.h - ABI structures for executors --------------*- C++ -*-===//
// This source file is part of the open source project
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
// See for license information
// See for the list of Swift project authors
// Swift ABI describing executors.
#include <inttypes.h>
#include "swift/ABI/HeapObject.h"
namespace swift {
class AsyncContext;
class AsyncTask;
class DefaultActor;
class Job;
/// An ExecutorRef isn't necessarily just a pointer to an executor
/// object; it may have other bits set.
class ExecutorRef {
static constexpr uintptr_t IsDefaultActor = 1;
static constexpr uintptr_t PointerMask = 7;
uintptr_t Value;
constexpr ExecutorRef(uintptr_t value) : Value(value) {}
/// A generic execution environment. When running in a generic
/// environment, it's presumed to be okay to switch synchronously
/// to an actor. As an executor request, this represents a request
/// to drop whatever the current actor is.
constexpr static ExecutorRef generic() {
return ExecutorRef(0);
/// Given a pointer to a default actor, return an executor reference
/// for it.
static ExecutorRef forDefaultActor(DefaultActor *actor) {
return ExecutorRef(reinterpret_cast<uintptr_t>(actor) | IsDefaultActor);
/// Is this the generic executor reference?
bool isGeneric() const {
return Value == 0;
/// Is this a default-actor executor reference?
bool isDefaultActor() const {
return Value & IsDefaultActor;
DefaultActor *getDefaultActor() const {
return reinterpret_cast<DefaultActor*>(Value & ~PointerMask);
uintptr_t getRawValue() const {
return Value;
/// Do we have to do any work to start running as the requested
/// executor?
bool mustSwitchToRun(ExecutorRef newExecutor) const {
return *this != newExecutor;
bool operator==(ExecutorRef other) const {
return Value == other.Value;
bool operator!=(ExecutorRef other) const {
return Value != other.Value;
using JobInvokeFunction =
void (Job *, ExecutorRef);
using TaskContinuationFunction =
void (AsyncTask *, ExecutorRef, AsyncContext *);
template <class AsyncSignature>
class AsyncFunctionPointer;
template <class AsyncSignature>
struct AsyncFunctionTypeImpl;
/// The abstract signature for an asynchronous function.
template <class Sig, bool HasErrorResult>
struct AsyncSignature;
template <class DirectResultTy, class... ArgTys, bool HasErrorResult>
struct AsyncSignature<DirectResultTy(ArgTys...), HasErrorResult> {
bool hasDirectResult = !std::is_same<DirectResultTy, void>::value;
using DirectResultType = DirectResultTy;
bool hasErrorResult = HasErrorResult;
using FunctionPointer = AsyncFunctionPointer<AsyncSignature>;
using FunctionType = typename AsyncFunctionTypeImpl<AsyncSignature>::type;
/// A signature for a thin async function that takes no arguments
/// and returns no results.
using ThinNullaryAsyncSignature =
AsyncSignature<void(), false>;
/// A signature for a thick async function that takes no formal
/// arguments and returns no results.
using ThickNullaryAsyncSignature =
AsyncSignature<void(HeapObject*), false>;
/// A class which can be used to statically query whether a type
/// is a specialization of AsyncSignature.
template <class T>
struct IsAsyncSignature {
static const bool value = false;
template <class DirectResultTy, class... ArgTys, bool HasErrorResult>
struct IsAsyncSignature<AsyncSignature<DirectResultTy(ArgTys...),
HasErrorResult>> {
static const bool value = true;
template <class Signature>
struct AsyncFunctionTypeImpl {
"template argument is not an AsyncSignature");
// TODO: expand and include the arguments in the parameters.
using type = TaskContinuationFunction;
template <class Fn>
using AsyncFunctionType = typename AsyncFunctionTypeImpl<Fn>::type;
/// A "function pointer" for an async function.
/// Eventually, this will always be signed with the data key
/// using a type-specific discriminator.
template <class AsyncSignature>
class AsyncFunctionPointer {
/// The function to run.
/*nullable*/ false,
int32_t> Function;
/// The expected size of the context.
uint32_t ExpectedContextSize;