123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- #pragma warning disable CS1591
- using Cysharp.Threading.Tasks.Internal;
- using System;
- using System.Linq;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- namespace Cysharp.Threading.Tasks.CompilerServices
- {
- // #ENABLE_IL2CPP in this file is to avoid bug of IL2CPP VM.
- // Issue is tracked on https://issuetracker.unity3d.com/issues/il2cpp-incorrect-results-when-calling-a-method-from-outside-class-in-a-struct
- // but currently it is labeled `Won't Fix`.
- internal interface IStateMachineRunner
- {
- Action MoveNext { get; }
- void Return();
- #if ENABLE_IL2CPP
- Action ReturnAction { get; }
- #endif
- }
- internal interface IStateMachineRunnerPromise : IUniTaskSource
- {
- Action MoveNext { get; }
- UniTask Task { get; }
- void SetResult();
- void SetException(Exception exception);
- }
- internal interface IStateMachineRunnerPromise<T> : IUniTaskSource<T>
- {
- Action MoveNext { get; }
- UniTask<T> Task { get; }
- void SetResult(T result);
- void SetException(Exception exception);
- }
- internal static class StateMachineUtility
- {
- // Get AsyncStateMachine internal state to check IL2CPP bug
- public static int GetState(IAsyncStateMachine stateMachine)
- {
- var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
- .First(x => x.Name.EndsWith("__state"));
- return (int)info.GetValue(stateMachine);
- }
- }
- internal sealed class AsyncUniTaskVoid<TStateMachine> : IStateMachineRunner, ITaskPoolNode<AsyncUniTaskVoid<TStateMachine>>, IUniTaskSource
- where TStateMachine : IAsyncStateMachine
- {
- static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
- #if ENABLE_IL2CPP
- public Action ReturnAction { get; }
- #endif
- TStateMachine stateMachine;
- public Action MoveNext { get; }
- public AsyncUniTaskVoid()
- {
- MoveNext = Run;
- #if ENABLE_IL2CPP
- ReturnAction = Return;
- #endif
- }
- public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef)
- {
- if (!pool.TryPop(out var result))
- {
- result = new AsyncUniTaskVoid<TStateMachine>();
- }
- TaskTracker.TrackActiveTask(result, 3);
- runnerFieldRef = result; // set runner before copied.
- result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
- }
- static AsyncUniTaskVoid()
- {
- TaskPool.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
- }
- AsyncUniTaskVoid<TStateMachine> nextNode;
- public ref AsyncUniTaskVoid<TStateMachine> NextNode => ref nextNode;
- public void Return()
- {
- TaskTracker.RemoveTracking(this);
- stateMachine = default;
- pool.TryPush(this);
- }
- [DebuggerHidden]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- void Run()
- {
- stateMachine.MoveNext();
- }
- // dummy interface implementation for TaskTracker.
- UniTaskStatus IUniTaskSource.GetStatus(short token)
- {
- return UniTaskStatus.Pending;
- }
- UniTaskStatus IUniTaskSource.UnsafeGetStatus()
- {
- return UniTaskStatus.Pending;
- }
- void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
- {
- }
- void IUniTaskSource.GetResult(short token)
- {
- }
- }
- internal sealed class AsyncUniTask<TStateMachine> : IStateMachineRunnerPromise, IUniTaskSource, ITaskPoolNode<AsyncUniTask<TStateMachine>>
- where TStateMachine : IAsyncStateMachine
- {
- static TaskPool<AsyncUniTask<TStateMachine>> pool;
- #if ENABLE_IL2CPP
- readonly Action returnDelegate;
- #endif
- public Action MoveNext { get; }
- TStateMachine stateMachine;
- UniTaskCompletionSourceCore<AsyncUnit> core;
- AsyncUniTask()
- {
- MoveNext = Run;
- #if ENABLE_IL2CPP
- returnDelegate = Return;
- #endif
- }
- public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef)
- {
- if (!pool.TryPop(out var result))
- {
- result = new AsyncUniTask<TStateMachine>();
- }
- TaskTracker.TrackActiveTask(result, 3);
- runnerPromiseFieldRef = result; // set runner before copied.
- result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
- }
- AsyncUniTask<TStateMachine> nextNode;
- public ref AsyncUniTask<TStateMachine> NextNode => ref nextNode;
- static AsyncUniTask()
- {
- TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
- }
- void Return()
- {
- TaskTracker.RemoveTracking(this);
- core.Reset();
- stateMachine = default;
- pool.TryPush(this);
- }
- bool TryReturn()
- {
- TaskTracker.RemoveTracking(this);
- core.Reset();
- stateMachine = default;
- return pool.TryPush(this);
- }
- [DebuggerHidden]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- void Run()
- {
- stateMachine.MoveNext();
- }
- public UniTask Task
- {
- [DebuggerHidden]
- get
- {
- return new UniTask(this, core.Version);
- }
- }
- [DebuggerHidden]
- public void SetResult()
- {
- core.TrySetResult(AsyncUnit.Default);
- }
- [DebuggerHidden]
- public void SetException(Exception exception)
- {
- core.TrySetException(exception);
- }
- [DebuggerHidden]
- public void GetResult(short token)
- {
- try
- {
- core.GetResult(token);
- }
- finally
- {
- #if ENABLE_IL2CPP
- // workaround for IL2CPP bug.
- PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
- #else
- TryReturn();
- #endif
- }
- }
- [DebuggerHidden]
- public UniTaskStatus GetStatus(short token)
- {
- return core.GetStatus(token);
- }
- [DebuggerHidden]
- public UniTaskStatus UnsafeGetStatus()
- {
- return core.UnsafeGetStatus();
- }
- [DebuggerHidden]
- public void OnCompleted(Action<object> continuation, object state, short token)
- {
- core.OnCompleted(continuation, state, token);
- }
- }
- internal sealed class AsyncUniTask<TStateMachine, T> : IStateMachineRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>>
- where TStateMachine : IAsyncStateMachine
- {
- static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
- #if ENABLE_IL2CPP
- readonly Action returnDelegate;
- #endif
- public Action MoveNext { get; }
- TStateMachine stateMachine;
- UniTaskCompletionSourceCore<T> core;
- AsyncUniTask()
- {
- MoveNext = Run;
- #if ENABLE_IL2CPP
- returnDelegate = Return;
- #endif
- }
- public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise<T> runnerPromiseFieldRef)
- {
- if (!pool.TryPop(out var result))
- {
- result = new AsyncUniTask<TStateMachine, T>();
- }
- TaskTracker.TrackActiveTask(result, 3);
- runnerPromiseFieldRef = result; // set runner before copied.
- result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
- }
- AsyncUniTask<TStateMachine, T> nextNode;
- public ref AsyncUniTask<TStateMachine, T> NextNode => ref nextNode;
- static AsyncUniTask()
- {
- TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
- }
- void Return()
- {
- TaskTracker.RemoveTracking(this);
- core.Reset();
- stateMachine = default;
- pool.TryPush(this);
- }
- bool TryReturn()
- {
- TaskTracker.RemoveTracking(this);
- core.Reset();
- stateMachine = default;
- return pool.TryPush(this);
- }
- [DebuggerHidden]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- void Run()
- {
- // UnityEngine.Debug.Log($"MoveNext State:" + StateMachineUtility.GetState(stateMachine));
- stateMachine.MoveNext();
- }
- public UniTask<T> Task
- {
- [DebuggerHidden]
- get
- {
- return new UniTask<T>(this, core.Version);
- }
- }
- [DebuggerHidden]
- public void SetResult(T result)
- {
- core.TrySetResult(result);
- }
- [DebuggerHidden]
- public void SetException(Exception exception)
- {
- core.TrySetException(exception);
- }
- [DebuggerHidden]
- public T GetResult(short token)
- {
- try
- {
- return core.GetResult(token);
- }
- finally
- {
- #if ENABLE_IL2CPP
- // workaround for IL2CPP bug.
- PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
- #else
- TryReturn();
- #endif
- }
- }
- [DebuggerHidden]
- void IUniTaskSource.GetResult(short token)
- {
- GetResult(token);
- }
- [DebuggerHidden]
- public UniTaskStatus GetStatus(short token)
- {
- return core.GetStatus(token);
- }
- [DebuggerHidden]
- public UniTaskStatus UnsafeGetStatus()
- {
- return core.UnsafeGetStatus();
- }
- [DebuggerHidden]
- public void OnCompleted(Action<object> continuation, object state, short token)
- {
- core.OnCompleted(continuation, state, token);
- }
- }
- }
|