This commit changes JobFlags storage to be 32bits, but leaves the runtime
API expressed in terms of size_t. This allows us to pack an Id in the
32bits we freed up.
The offset of this Id in the AsyncTask is an ABI constant. This way
introspection tools can extract the currently running task identifier
without any need for special APIs.
This adjusts the IRGen layer to accommodate the Windows linking model.
We assume dynamic linking by default. The static linking is enabled by
passing `-static` to the driver, which forwards it to the frontend when
building the module statically. This has already been required when
generating libraries, however, the non-Windows targets are more
forgiving and let it work. On those platforms, using this hint would
allow for more efficient code generation, reducing load times and some
runtime penalties from the PLT and GOT references formed to symbols
which are module local.
This corrects static linking on Windows, which is one of the last few
items that are missing on Windows. It also takes advantage of the hint
for the one peculiar difference between Windows and non-Windows:
protocol conformances that span module boundaries are not available as a
constant. However, when statically linking, we can enable those
conformances to be statically resolved. This should enable the last
known pattern to work when using static linking.
This support requires further work in the Swift Package Manager to
actually enable building libraries properly. However, when building
with CMake, this should be sufficient to enable static linking.
Previously, they were storing a low-bit flag that indicated that they
were a default actor. Using an extra inhabitant frees up the low bit
for future use without being conspicuously more expensive to check.
- Introduce an UnownedSerialExecutor type into the concurrency library.
- Create a SerialExecutor protocol which allows an executor type to
change how it executes jobs.
- Add an unownedExecutor requirement to the Actor protocol.
- Change the ABI for ExecutorRef so that it stores a SerialExecutor
witness table pointer in the implementation field. This effectively
makes ExecutorRef an `unowned(unsafe) SerialExecutor`, except that
default actors are represented without a witness table pointer (just
a bit-pattern).
- Synthesize the unownedExecutor method for default actors (i.e. actors
that don't provide an unownedExecutor property).
- Make synthesized unownedExecutor properties `final`, and give them
a semantics attribute specifying that they're for default actors.
- Split `Builtin.buildSerialExecutorRef` into a few more precise
builtins. We're not using the main-actor one yet, though.
Pitch thread:
https://forums.swift.org/t/support-custom-executors-in-swift-concurrency/44425
Allow runtime metadata queries to determine if a "class" (in the
runtime) is actually an actor by adding a bit to the class context
descriptor's type-specific kind flags.
Implements rdar://77073762.
* Add explicit calling convention on builtin GetCurrentTask
This builtin function emits a call of swift_task_getCurrent, and user
code can declare the same name function with slightly different
signature at LLVM level (data size should be same) using @_silgen_name.
In that case, IRGen insert cast inst to cast the function to the
expected signature. But this cast inst drops calling convention info, so
call inst was emitted without swiftcc.
This patch changed to emit a call of swift_task_getCurrent with the
explicit calling convention.
* Add test case to ensure builtin function cc when conflict
Commit the platform definition and build script work necessary to
cross-compile for arm64_32.
arm64_32 is a variant of AARCH64 that supports an ILP32 architecture.
When the closure of startAsyncLet is no-escaping, the captured values (= the partial_apply arguments) must be kept alive until the endAsyncLet builtin.
ClosureLifetimeFixup adds the generated mark_dependence as a second operand to endAsyncLet, which keeps all the arguments alive until this point.
Instead, put the archetype->instrution map into SIlModule.
SILOpenedArchetypesTracker tried to maintain and reconstruct the mapping locally, e.g. during a use of SILBuilder.
Having a "global" map in SILModule makes the whole logic _much_ simpler.
I'm wondering why we didn't do this in the first place.
This requires that opened archetypes must be unique in a module - which makes sense. This was the case anyway, except for keypath accessors (which I fixed in the previous commit) and in some sil test files.
... with a fix for a non-assert build crash: I used the wrong ilist type for SlabList. This does not explain the crash, though. What I think happened here is that llvm miscompiled and put the llvm_unreachable from the Slab's deleteNode function unconditionally into the SILModule destructor.
Now by using simple_ilist, there is no need for a deleteNode at all.
Through various means, it is possible for a synchronous actor-isolated
function to escape to another concurrency domain and be called from
outside the actor. The problem existed previously, but has become far
easier to trigger now that `@escaping` closures and local functions
can be actor-isolated.
Introduce runtime detection of such data races, where a synchronous
actor-isolated function ends up being called from the wrong executor.
Do this by emitting an executor check in actor-isolated synchronous
functions, where we query the executor in thread-local storage and
ensure that it is what we expect. If it isn't, the runtime complains.
The runtime's complaints can be controlled with the environment
variable `SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL`:
0 - disable checking
1 - warn when a data race is detected
2 - error and abort when a data race is detected
At an implementation level, this introduces a new concurrency runtime
entry point `_checkExpectedExecutor` that checks the given executor
(on which the function should always have been called) against the
executor on which is called (which is in thread-local storage). There
is a special carve-out here for `@MainActor` code, where we check
against the OS's notion of "main thread" as well, so that `@MainActor`
code can be called via (e.g.) the Dispatch library's
`DispatchQueue.main.async`.
The new SIL instruction `extract_executor` performs the lowering of an
actor down to its executor, which is implicit in the `hop_to_executor`
instruction. Extend the LowerHopToExecutor pass to perform said
lowering.
Otherwise, the runtime needs to be able to adjust the instance size when nonfragile ObjC bases
and/or resilient Swift bases are accounted for. rdar://54089488
Previously, the partial application of a generic method at the receiver
would result in the emission of a "simple" partial apply where the
receiver was treated as the context and the original function was
treated as the function. That was problematic because such partial
applications must capture the polymorphic arguments supplied at
partial_apply time. Here, a full partial application forwarder is
emitted for this case.
rdar://76479222
As part of bringup, specifically in order to support storing the size of
the async context as the first entry in the thick context, the
optimization that allows the partial application of a single refcounted
object to avoid the allocation of a thick context was disabled.
Now that we have async function pointers for partial application
forwarders, that rationale is moot, so, here, the optimization is
restored.
rdar://76372871
- stop storing the parent task in the TaskGroup at the .swift level
- make sure that swift_taskGroup_isCancelled is implied by the parent
task being cancelled
- make the TaskGroup structs frozen
- make the withTaskGroup functions inlinable
- remove swift_taskGroup_create
- teach IRGen to allocate memory for the task group
- don't deallocate the task group in swift_taskGroup_destroy
To achieve the allocation change, introduce paired create/destroy builtins.
Furthermore, remove the _swiftRetain and _swiftRelease functions and
several calls to them. Replace them with uses of the appropriate builtins.
I should probably change the builtins to return retained, since they're
working with a managed type, but I'll do that in a separate commit.
Previously, the method table would contain duplicate copies due to the
ProtocolDecl carrying a completionHandler-based version of the method,
as well as the async version of the method.
Fixes rdar://76192003.
For ordinary memory-management reasons, this should only ever
happen when there will be no more uses of the actor outside of the
actor runtime. The actor runtime, meanwhile, doesn't care about
anything except the default-actor control state of the actor. So
we can just allow the rest of the actor to be destructed when it
isn't needed anymore, then destroy the actor state and deallocate
the object when we get around to switching off the executor.
This does assume that the task doesn't do anything which semantically
detects the executor it's on before switching off it, since doing so
might read a bogus executor. However, we should only get an executor
in a zombie state like this when a hop has been removed or reordered,
and detection events should count as inhibiting that and forcing the
true executor to be switched to (and thus detected).
(But maybe lifetime optimization can make this happen? Maybe we
need semantic detection to filter out zombie executors.)