Files
swift-mirror/stdlib/toolchain/Compatibility56/include/Concurrency/Executor.h
2022-09-01 10:07:44 -07:00

222 lines
7.1 KiB
C++

//===--- Executor.h - ABI structures for executors --------------*- C++ -*-===//
//
// This source file is part of the Swift.org 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 https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Swift ABI describing executors.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_ABI_EXECUTOR_BACKDEPLOY56_H
#define SWIFT_ABI_EXECUTOR_BACKDEPLOY56_H
#include <inttypes.h>
#include "Actor.h"
#include "swift/ABI/HeapObject.h"
#include "swift/Runtime/Casting.h"
namespace swift {
class AsyncContext;
class AsyncTask;
class DefaultActor;
class Job;
class SerialExecutorWitnessTable;
/// An unmanaged reference to an executor.
///
/// This type corresponds to the type Optional<Builtin.Executor> in
/// Swift. The representation of nil in Optional<Builtin.Executor>
/// aligns with what this type calls the generic executor, so the
/// notional subtype of this type which is never generic corresponds
/// to the type Builtin.Executor.
///
/// An executor reference is divided into two pieces:
///
/// - The identity, which is just a (potentially ObjC) object
/// reference; when this is null, the reference is generic.
/// Equality of executor references is based solely on equality
/// of identity.
///
/// - The implementation, which is an optional reference to a
/// witness table for the SerialExecutor protocol. When this
/// is null, but the identity is non-null, the reference is to
/// a default actor. The low bits of the implementation pointer
/// are reserved for the use of marking interesting properties
/// about the executor's implementation. The runtime masks these
/// bits off before accessing the witness table, so setting them
/// in the future should back-deploy as long as the witness table
/// reference is still present.
class ExecutorRef {
HeapObject *Identity; // Not necessarily Swift reference-countable
uintptr_t Implementation;
// We future-proof the ABI here by masking the low bits off the
// implementation pointer before using it as a witness table.
enum: uintptr_t {
WitnessTableMask = ~uintptr_t(alignof(void*) - 1)
};
constexpr ExecutorRef(HeapObject *identity, uintptr_t implementation)
: Identity(identity), Implementation(implementation) {}
public:
/// 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(nullptr, 0);
}
/// Given a pointer to a default actor, return an executor reference
/// for it.
static ExecutorRef forDefaultActor(DefaultActor *actor) {
assert(actor);
return ExecutorRef(actor, 0);
}
/// Given a pointer to a serial executor and its SerialExecutor
/// conformance, return an executor reference for it.
static ExecutorRef forOrdinary(HeapObject *identity,
const SerialExecutorWitnessTable *witnessTable) {
assert(identity);
assert(witnessTable);
return ExecutorRef(identity, reinterpret_cast<uintptr_t>(witnessTable));
}
HeapObject *getIdentity() const {
return Identity;
}
/// Is this the generic executor reference?
bool isGeneric() const {
return Identity == 0;
}
/// Is this a default-actor executor reference?
bool isDefaultActor() const {
return !isGeneric() && Implementation == 0;
}
DefaultActor *getDefaultActor() const {
assert(isDefaultActor());
return reinterpret_cast<DefaultActor*>(Identity);
}
const SerialExecutorWitnessTable *getSerialExecutorWitnessTable() const {
assert(!isGeneric() && !isDefaultActor());
auto table = Implementation & WitnessTableMask;
return reinterpret_cast<const SerialExecutorWitnessTable*>(table);
}
/// Do we have to do any work to start running as the requested
/// executor?
bool mustSwitchToRun(ExecutorRef newExecutor) const {
return Identity != newExecutor.Identity;
}
/// Is this executor the main executor?
bool isMainExecutor() const;
bool operator==(ExecutorRef other) const {
return Identity == other.Identity;
}
bool operator!=(ExecutorRef other) const {
return !(*this == other);
}
};
using JobInvokeFunction =
SWIFT_CC(swiftasync)
void (Job *);
using TaskContinuationFunction =
SWIFT_CC(swiftasync)
void (SWIFT_ASYNC_CONTEXT AsyncContext *);
using ThrowingTaskFutureWaitContinuationFunction =
SWIFT_CC(swiftasync)
void (SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT void *);
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 {
static_assert(IsAsyncSignature<Signature>::value,
"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 {
public:
/// The function to run.
RelativeDirectPointer<AsyncFunctionType<AsyncSignature>,
/*nullable*/ false,
int32_t> Function;
/// The expected size of the context.
uint32_t ExpectedContextSize;
};
}
#endif // SWIFT_ABI_EXECUTOR_BACKDEPLOY56_H