//===--- 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_H #define SWIFT_ABI_EXECUTOR_H #include #include "swift/ABI/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 in /// Swift. The representation of nil in Optional /// 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. // // We have 3 bits for future use remaining here. enum: uintptr_t { WitnessTableMask = ~uintptr_t(alignof(void*) - 1) }; /// The kind is stored in the free bits in the `Implementation` witness table reference. enum class ExecutorKind : uintptr_t { /// Ordinary executor. /// /// Note that the "Generic" executor is also implicitly "Ordinary". /// To check if an executor is Generic, explicitly check this by calling `isGeneric`. Ordinary = 0b00, /// Executor that may need to participate in complex "same context" checks, /// by invoking `isSameExclusiveExecutionContext` when comparing execution contexts. ComplexEquality = 0b01, }; static_assert(static_cast(ExecutorKind::Ordinary) == 0); 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); auto wtable = reinterpret_cast(witnessTable) | static_cast(ExecutorKind::Ordinary); return ExecutorRef(identity, wtable); } static ExecutorRef forComplexEquality(HeapObject *identity, const SerialExecutorWitnessTable *witnessTable) { assert(identity); assert(witnessTable); auto wtable = reinterpret_cast(witnessTable) | static_cast(ExecutorKind::ComplexEquality); return ExecutorRef(identity, wtable); } HeapObject *getIdentity() const { return Identity; } /// Is this the generic executor reference? bool isGeneric() const { return Identity == 0; } ExecutorKind getExecutorKind() const { return static_cast(Implementation & ~WitnessTableMask); } /// Is this an ordinary executor reference? /// These executor references are the default kind, and have no special treatment elsewhere in the system. bool isOrdinary() const { return getExecutorKind() == ExecutorKind::Ordinary; } /// Is this an `complex-equality` executor reference? /// These executor references should implement `isSameExclusiveExecutionContext` which will be invoked /// when two executors are compared for being the same exclusive execution context. bool isComplexEquality() const { return getExecutorKind() == ExecutorKind::ComplexEquality; } /// Is this a default-actor executor reference? bool isDefaultActor() const { return !isGeneric() && Implementation == 0; } DefaultActor *getDefaultActor() const { assert(isDefaultActor()); return reinterpret_cast(Identity); } const SerialExecutorWitnessTable *getSerialExecutorWitnessTable() const { assert(!isGeneric() && !isDefaultActor()); auto table = Implementation & WitnessTableMask; return reinterpret_cast(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; /// Get the raw value of the Implementation field, for tracing. uintptr_t getRawImplementation() const { return Implementation & WitnessTableMask; } 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 AsyncFunctionPointer; template struct AsyncFunctionTypeImpl; template struct AsyncContinuationTypeImpl; /// The abstract signature for an asynchronous function. template struct AsyncSignature; template struct AsyncSignature { bool hasDirectResult = !std::is_same::value; using DirectResultType = DirectResultTy; bool hasErrorResult = HasErrorResult; using FunctionPointer = AsyncFunctionPointer; using FunctionType = typename AsyncFunctionTypeImpl::type; using ContinuationType = typename AsyncContinuationTypeImpl::type; }; /// A signature for a thin async function that takes no arguments /// and returns no results. using ThinNullaryAsyncSignature = AsyncSignature; /// A signature for a thick async function that takes no formal /// arguments and returns no results. using ThickNullaryAsyncSignature = AsyncSignature; template struct AsyncFunctionTypeImpl; template struct AsyncFunctionTypeImpl< AsyncSignature> { using type = SWIFT_CC(swiftasync) void(SWIFT_ASYNC_CONTEXT AsyncContext *, ArgTys...); }; template struct AsyncContinuationTypeImpl; template struct AsyncContinuationTypeImpl< AsyncSignature> { using type = SWIFT_CC(swiftasync) void(SWIFT_ASYNC_CONTEXT AsyncContext *, DirectResultTy, SWIFT_CONTEXT void *); }; template struct AsyncContinuationTypeImpl< AsyncSignature> { using type = SWIFT_CC(swiftasync) void(SWIFT_ASYNC_CONTEXT AsyncContext *, DirectResultTy); }; template struct AsyncContinuationTypeImpl< AsyncSignature> { using type = SWIFT_CC(swiftasync) void(SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT SwiftError *); }; template struct AsyncContinuationTypeImpl< AsyncSignature> { using type = SWIFT_CC(swiftasync) void(SWIFT_ASYNC_CONTEXT AsyncContext *); }; template using AsyncFunctionType = typename AsyncFunctionTypeImpl::type; template using AsyncContinuationType = typename AsyncContinuationTypeImpl::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 AsyncFunctionPointer { public: /// The function to run. TargetCompactFunctionPointer, /*nullable*/ false, int32_t> Function; /// The expected size of the context. uint32_t ExpectedContextSize; }; } #endif