Previously, thick async functions were represented sometimes as a pair
of (AsyncFunctionPointer, nullptr)--when the thick function was produced
via a thin_to_thick_function, e.g.--and sometimes as a pair of
(FunctionPointer, ThickContext)--when the thick function was produced by
a partial_apply--with the size stored in the slot of the ThickContext.
That optimized for the wrong case: partial applies of dynamic async
functions; in that case, there is no appropriate AsyncFunctionPointer to
form when lowering the partial_apply instruction. The far more common
case is to know exactly which function is being partially applied. In
that case, we can form the appropriate AsyncFunctionPointer.
Furthermore, the previous representation made calling a thick function
more complex: it was always necessary to check whether the context was
in fact null and then proceed along two different paths depending.
Here, that behavior is corrected by creating a thunk in a mandatory
IRGen SIL pass in the case that the function that is being partially
applied is dynamic. That new thunk is then partially applied in place
of the original partial_apply of the dynamic function.
Create a TargetDispatchClassMetadata for Swift metadata that also has a dispatch-compatible vtable. Dispatch leaves room for ObjC class metadata so the two regions don't overlap. (The vtable currently consists of a single dummy entry; this will be filled out later.)
Rearrange the Job and AsyncTask hierarchy so that AsyncTask inherits only from Job, which in turn inherits from HeapObject. This gives all Job instances a dispatch-compatible isa field. It also gives them a refcount word, which is wasted on instances that aren't AsyncTask instances. Maybe we can find some use for that space in the future.
rdar://75227953
In their previous form, the non-`_f` variants of these entry points were unused, and IRGen
lowered the `createAsyncTask` builtins to use the `_f` variants with a large amount of caller-side
codegen to manually unpack closure values. Amid all this, it also failed to make anyone responsible
for releasing the closure context after the task completed, causing every task creation to leak.
Redo the `swift_task_create_*` entry points to accept the two words of an async closure value
directly, and unpack the closure to get its invocation entry point and initial context size
inside the runtime. (Also get rid of the non-future `swift_task_create` variant, since it's unused
and it's subtly different in a lot of hairy ways from the future forms. Better to add it later
when it's needed than to have a broken unexercised version now.)
I'm about to replace these with new variations that correctly handle spawning a task with
a closure as its initial entry point, without leaking or requiring large amounts of caller-side
code generation.
I have identified the following conceptual synchronization points at
which task data and computation can cross thread boundaries. We need to
model these in TSan to avoid false positives:
Awaiting an async task (`AsyncTask::waitFuture`), which has two cases:
1) The task has completed (`AsyncTask::completeFuture`). Everything
that happened during task execution "happened before" before the
point where we access its result. We synchronize on the *awaited*
task.
2) The task is still executing: the current execution is suspended and
the waiting task is put into the list of "waiters". Once the awaited
task completes, the waiters will be scheduled. In this case, we
synchronize on the *waiting* task.
Note: there is a similar relationship for task groups which I still have
to investigate. I will follow-up with an additional patch and tests.
Actor job execution (`swift::runJobInExecutorContext`):
Job scheduling (`swift::swift_task_enqueue`) precedes/happens before job
execution. Also all job executions (switching actors or suspend/resume)
are serially ordered.
Note: the happens-before edge for schedule->execute isn't strictly
needed in most cases since scheduling calls through to libdispatch's
`dispatch_async_f`, which we already intercept and model in TSan.
However, I am trying to model Swift Task semantics to increase the
chance of things to continue to work in case the "task backend" is
switched out.
rdar://74256733
First, just call an async -> T function instead of forcing the caller
to piece together which case we're in and perform its own copy. This
ensures that the task is actually kept alive properly.
Second, now that we no longer implicitly depend on the waiting tasks
being run synchronously, go ahead and schedule them to run on the
global executor.
This solves some problems which were blocking the work on TLS-ifying
the task/executor state.
This is conditional on UseAsyncLowering and in the future should also be
conditional on `clangTargetInfo.isSwiftAsyncCCSupported()` once that
support is merged.
Update tests to work either with swiftcc or swifttailcc.
Previously, the error stored in the async context was of type SwiftError
*. In order to enable the context to be callee released, make it
indirect and change its type to SwiftError **.
rdar://71378532
Debugging tools can use _swift_concurrency_debug_asyncTaskMetadata to identify memory blocks as async task allocations by looking at their isa/metadata pointer.
rdar://72906895
The CoreFoundation implementation on non-Darwin platforms included in
Foundation is not meant to be used as a general purpose CoreFoundation
implementation. Since non-Darwin targets do not default to providing a
CoreFoundation implementation, we should generally assume that the
symbol is not present. This changes the non-Darwin paths to always use
`dispatch_main` rather than `CFRunLoopRun`.
When built in single threaded mode, the runtime does not use dispatch to
queue the tasks. As a result, pumping the dispatch main queue will
simply wait indefinitely. In the single threaded mode, simply halt
execution and drain all pending tasks before returning. This allows
forward progress in the single threaded mode.
Rather than just simply invoking abort on Windows, attempt to load
dispatch and execute the main loop by looking up `dispatch_main` in the
module. Assuming that dispatch was used already, the `LoadLibraryW`
will provide the handle to the module currently mapped in. This still
is not correct, since we do not link to libdispatch, so we cannot have
invoked any dispatch queuing methods. However, this is better than the
previous behaviour of simply aborting.
This resolves the symptom in SR-14086, but not the underlying problem.
* Adds support for generating code that uses swiftasync parameter lowering.
* Currently only arm64's llvm lowering supports the swift_async_context_addr intrinsic.
* Add arm64e pointer signing of updated swift_async_context_addr.
This commit needs the PR llvm-project#2291.
* [runtime] unittests should use just-built compiler if the runtime did
This will start to matter with the introduction of usage of swiftasync parameters which only very recent compilers support.
rdar://71499498
Windows doesn't have dlsym. Since I don't have a Windows box, I'm just
if-def'ing it out for the time being. Since we don't want Windows going
off and doing dangerous things, I threw in an abort just to be safe.
Adding execution and death test to ensure that we crash appropriately
when the main function throws an uncaught exception, and that the async
main runs correctly.
Also switching to doing the CFRunLoopRun lookup with `RTLD_DEFAULT`
since `RTLD_SELF` isn't available on Linux.
Switching to `try await` since `await try` is no longer the right way to
do that.
Using exit(0) instead of EXIT_SUCCESS since the C++ importer doesn't
mark imported macros with @actorIndependent yet.
This patch has two desirable effects for the price of one.
1. An uncaught error thrown from main will now explode
2. Move us off of using runAsyncAndBlock
The issue with runAsyncAndBlock is that it blocks the main thread
outright. UI and the main actor need to run on the main thread or bad
things happen, so blocking the main thread results in a bad day for
them.
Instead, we're using CFRunLoopRun to run the core-foundation run loop on
the main thread, or, dispatch_main if CFRunLoopRun isn't available.
The issue with just using dispatch_main is that it doesn't actually
guarantee that it will run the tasks on the main thread either, just
that it clears the main queue. We don't want to require everything that
uses concurrency to have to include CoreFoundation either, but dispatch
is already required, which supplies dispatch_main, which just empties
out the main queue.