//===--- 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 #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 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. 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(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(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; 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; /// 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; }; /// 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; /// A class which can be used to statically query whether a type /// is a specialization of AsyncSignature. template struct IsAsyncSignature { static const bool value = false; }; template struct IsAsyncSignature> { static const bool value = true; }; template struct AsyncFunctionTypeImpl { static_assert(IsAsyncSignature::value, "template argument is not an AsyncSignature"); // TODO: expand and include the arguments in the parameters. using type = TaskContinuationFunction; }; template using AsyncFunctionType = typename AsyncFunctionTypeImpl::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. RelativeDirectPointer, /*nullable*/ false, int32_t> Function; /// The expected size of the context. uint32_t ExpectedContextSize; }; } #endif // SWIFT_ABI_EXECUTOR_BACKDEPLOY56_H