3737#include " llvm/Config/config.h"
3838#include " llvm/ADT/PointerIntPair.h"
3939#include " TaskPrivate.h"
40+ #include " VoucherSupport.h"
4041
4142#if !SWIFT_CONCURRENCY_COOPERATIVE_GLOBAL_EXECUTOR
4243#include < dispatch/dispatch.h>
@@ -132,6 +133,8 @@ class ExecutorTrackingInfo {
132133 // / unless the passed-in executor is generic.
133134 bool AllowsSwitching = true ;
134135
136+ VoucherManager voucherManager;
137+
135138 // / The tracking info that was active when this one was entered.
136139 ExecutorTrackingInfo *SavedInfo;
137140
@@ -150,23 +153,9 @@ class ExecutorTrackingInfo {
150153 ActiveInfoInThread.set (this );
151154 }
152155
153- // / Initialize a tracking state on the current thread if there
154- // / isn't one already, or else update the current tracking state.
155- // /
156- // / Returns a pointer to the active tracking info. If this is the
157- // / same as the object on which this was called, leave() must be
158- // / called before the object goes out of scope.
159- ExecutorTrackingInfo *enterOrUpdate (ExecutorRef currentExecutor) {
160- if (auto activeInfo = ActiveInfoInThread.get ()) {
161- activeInfo->ActiveExecutor = currentExecutor;
162- return activeInfo;
163- }
156+ void swapToJob (Job *job) { voucherManager.swapToJob (job); }
164157
165- ActiveExecutor = currentExecutor;
166- SavedInfo = nullptr ;
167- ActiveInfoInThread.set (this );
168- return this ;
169- }
158+ void restoreVoucher (AsyncTask *task) { voucherManager.restoreVoucher (task); }
170159
171160 ExecutorRef getActiveExecutor () const {
172161 return ActiveExecutor;
@@ -192,6 +181,7 @@ class ExecutorTrackingInfo {
192181 }
193182
194183 void leave () {
184+ voucherManager.leave ();
195185 ActiveInfoInThread.set (SavedInfo);
196186 }
197187};
@@ -242,7 +232,9 @@ void swift::runJobInEstablishedExecutorContext(Job *job) {
242232 assert (ActiveTask::get () == nullptr &&
243233 " active task wasn't cleared before susspending?" );
244234 } else {
245- // There's no extra bookkeeping to do for simple jobs.
235+ // There's no extra bookkeeping to do for simple jobs besides swapping in
236+ // the voucher.
237+ ExecutorTrackingInfo::current ()->swapToJob (job);
246238 job->runSimpleInFullyEstablishedContext ();
247239 }
248240
@@ -253,6 +245,14 @@ void swift::runJobInEstablishedExecutorContext(Job *job) {
253245 _swift_tsan_release (job);
254246}
255247
248+ void swift::adoptTaskVoucher (AsyncTask *task) {
249+ ExecutorTrackingInfo::current ()->swapToJob (task);
250+ }
251+
252+ void swift::restoreTaskVoucher (AsyncTask *task) {
253+ ExecutorTrackingInfo::current ()->restoreVoucher (task);
254+ }
255+
256256SWIFT_CC (swift)
257257AsyncTask *swift::swift_task_getCurrent() {
258258 return ActiveTask::get ();
@@ -676,6 +676,12 @@ class DefaultActorImpl : public HeapObject {
676676
677677 friend class ProcessInlineJob ;
678678 union {
679+ // When the ProcessInlineJob storage is initialized, its metadata pointer
680+ // will point to Job's metadata. When it isn't, the metadata pointer is
681+ // NULL. Use HeapObject to initialize the metadata pointer to NULL and allow
682+ // it to be checked without fully initializing the ProcessInlineJob.
683+ HeapObject JobStorageHeapObject{nullptr };
684+
679685 ProcessInlineJob JobStorage;
680686 };
681687
@@ -685,6 +691,7 @@ class DefaultActorImpl : public HeapObject {
685691 auto flags = Flags ();
686692 flags.setIsDistributedRemote (isDistributedRemote);
687693 new (&CurrentState) std::atomic<State>(State{JobRef (), flags});
694+ JobStorageHeapObject.metadata = nullptr ;
688695 }
689696
690697 // / Properly destruct an actor, except for the heap header.
@@ -812,6 +819,8 @@ void DefaultActorImpl::deallocate() {
812819}
813820
814821void DefaultActorImpl::deallocateUnconditional () {
822+ if (JobStorageHeapObject.metadata != nullptr )
823+ JobStorage.~ProcessInlineJob ();
815824 auto metadata = cast<ClassMetadata>(this ->metadata );
816825 swift_deallocObject (this , metadata->getInstanceSize (),
817826 metadata->getInstanceAlignMask ());
@@ -848,6 +857,8 @@ void DefaultActorImpl::scheduleNonOverrideProcessJob(JobPriority priority,
848857 if (hasActiveInlineJob) {
849858 job = new ProcessOutOfLineJob (this , priority);
850859 } else {
860+ if (JobStorageHeapObject.metadata != nullptr )
861+ JobStorage.~ProcessInlineJob ();
851862 job = new (&JobStorage) ProcessInlineJob (priority);
852863 }
853864 swift_task_enqueueGlobal (job);
@@ -1455,6 +1466,7 @@ static void swift_job_runImpl(Job *job, ExecutorRef executor) {
14551466
14561467 trackingInfo.enterAndShadow (executor);
14571468
1469+ SWIFT_TASK_DEBUG_LOG (" %s(%p)" , __func__, job);
14581470 runJobInEstablishedExecutorContext (job);
14591471
14601472 trackingInfo.leave ();
0 commit comments