diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
index 05850605b841..1c0392a27cd1 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
@@ -277,7 +277,7 @@ private Task Task
public struct AsyncTaskMethodBuilder
{
/// A cached VoidTaskResult task used for builders that complete synchronously.
- private readonly static Task s_cachedCompleted = AsyncTaskMethodBuilder.s_defaultResultTask;
+ private readonly static Task s_cachedCompleted = Task.s_defaultResultTask;
/// The generic builder object to which this non-generic instance delegates.
private AsyncTaskMethodBuilder m_builder; // mutable struct: must not be readonly
@@ -424,9 +424,6 @@ internal void SetNotificationForWaitCompletion(bool enabled)
[HostProtection(Synchronization = true, ExternalThreading = true)]
public struct AsyncTaskMethodBuilder
{
- /// A cached task for default(TResult).
- internal readonly static Task s_defaultResultTask = AsyncTaskCache.CreateCacheableTask(default(TResult));
-
// WARNING: For performance reasons, the m_task field is lazily initialized.
// For correct results, the struct AsyncTaskMethodBuilder must
// always be used from the same location/copy, at least until m_task is
@@ -594,8 +591,8 @@ public void SetResult(TResult result)
var task = m_task;
if (task == null)
{
- m_task = GetTaskForResult(result);
- Contract.Assert(m_task != null, "GetTaskForResult should never return null");
+ m_task = System.Threading.Tasks.Task.FromResult(result);
+ Contract.Assert(m_task != null, "Task.FromResult should never return null");
}
// Slow path: complete the existing task.
else
@@ -706,136 +703,6 @@ internal void SetNotificationForWaitCompletion(bool enabled)
/// when no other threads are in the middle of accessing this property or this.Task.
///
private object ObjectIdForDebugger { get { return this.Task; } }
-
- ///
- /// Gets a task for the specified result. This will either
- /// be a cached or new task, never null.
- ///
- /// The result for which we need a task.
- /// The completed task containing the result.
- [SecuritySafeCritical] // for JitHelpers.UnsafeCast
- private Task GetTaskForResult(TResult result)
- {
- Contract.Ensures(
- EqualityComparer.Default.Equals(result, Contract.Result>().Result),
- "The returned task's Result must return the same value as the specified result value.");
-
- // The goal of this function is to be give back a cached task if possible,
- // or to otherwise give back a new task. To give back a cached task,
- // we need to be able to evaluate the incoming result value, and we need
- // to avoid as much overhead as possible when doing so, as this function
- // is invoked as part of the return path from every async method.
- // Most tasks won't be cached, and thus we need the checks for those that are
- // to be as close to free as possible. This requires some trickiness given the
- // lack of generic specialization in .NET.
- //
- // Be very careful when modifying this code. It has been tuned
- // to comply with patterns recognized by both 32-bit and 64-bit JITs.
- // If changes are made here, be sure to look at the generated assembly, as
- // small tweaks can have big consequences for what does and doesn't get optimized away.
- //
- // Note that this code only ever accesses a static field when it knows it'll
- // find a cached value, since static fields (even if readonly and integral types)
- // require special access helpers in this NGEN'd and domain-neutral.
-
- if (null != (object)default(TResult)) // help the JIT avoid the value type branches for ref types
- {
- // Special case simple value types:
- // - Boolean
- // - Byte, SByte
- // - Char
- // - Decimal
- // - Int32, UInt32
- // - Int64, UInt64
- // - Int16, UInt16
- // - IntPtr, UIntPtr
- // As of .NET 4.5, the (Type)(object)result pattern used below
- // is recognized and optimized by both 32-bit and 64-bit JITs.
-
- // For Boolean, we cache all possible values.
- if (typeof(TResult) == typeof(Boolean)) // only the relevant branches are kept for each value-type generic instantiation
- {
- Boolean value = (Boolean)(object)result;
- Task task = value ? AsyncTaskCache.TrueTask : AsyncTaskCache.FalseTask;
- return JitHelpers.UnsafeCast>(task); // UnsafeCast avoids type check we know will succeed
- }
- // For Int32, we cache a range of common values, e.g. [-1,4).
- else if (typeof(TResult) == typeof(Int32))
- {
- // Compare to constants to avoid static field access if outside of cached range.
- // We compare to the upper bound first, as we're more likely to cache miss on the upper side than on the
- // lower side, due to positive values being more common than negative as return values.
- Int32 value = (Int32)(object)result;
- if (value < AsyncTaskCache.EXCLUSIVE_INT32_MAX &&
- value >= AsyncTaskCache.INCLUSIVE_INT32_MIN)
- {
- Task task = AsyncTaskCache.Int32Tasks[value - AsyncTaskCache.INCLUSIVE_INT32_MIN];
- return JitHelpers.UnsafeCast>(task); // UnsafeCast avoids a type check we know will succeed
- }
- }
- // For other known value types, we only special-case 0 / default(TResult).
- else if (
- (typeof(TResult) == typeof(UInt32) && default(UInt32) == (UInt32)(object)result) ||
- (typeof(TResult) == typeof(Byte) && default(Byte) == (Byte)(object)result) ||
- (typeof(TResult) == typeof(SByte) && default(SByte) == (SByte)(object)result) ||
- (typeof(TResult) == typeof(Char) && default(Char) == (Char)(object)result) ||
- (typeof(TResult) == typeof(Decimal) && default(Decimal) == (Decimal)(object)result) ||
- (typeof(TResult) == typeof(Int64) && default(Int64) == (Int64)(object)result) ||
- (typeof(TResult) == typeof(UInt64) && default(UInt64) == (UInt64)(object)result) ||
- (typeof(TResult) == typeof(Int16) && default(Int16) == (Int16)(object)result) ||
- (typeof(TResult) == typeof(UInt16) && default(UInt16) == (UInt16)(object)result) ||
- (typeof(TResult) == typeof(IntPtr) && default(IntPtr) == (IntPtr)(object)result) ||
- (typeof(TResult) == typeof(UIntPtr) && default(UIntPtr) == (UIntPtr)(object)result))
- {
- return s_defaultResultTask;
- }
- }
- else if (result == null) // optimized away for value types
- {
- return s_defaultResultTask;
- }
-
- // No cached task is available. Manufacture a new one for this result.
- return new Task(result);
- }
- }
-
- /// Provides a cache of closed generic tasks for async methods.
- internal static class AsyncTaskCache
- {
- // All static members are initialized inline to ensure type is beforefieldinit
-
- /// A cached Task{Boolean}.Result == true.
- internal readonly static Task TrueTask = CreateCacheableTask(true);
- /// A cached Task{Boolean}.Result == false.
- internal readonly static Task FalseTask = CreateCacheableTask(false);
-
- /// The cache of Task{Int32}.
- internal readonly static Task[] Int32Tasks = CreateInt32Tasks();
- /// The minimum value, inclusive, for which we want a cached task.
- internal const Int32 INCLUSIVE_INT32_MIN = -1;
- /// The maximum value, exclusive, for which we want a cached task.
- internal const Int32 EXCLUSIVE_INT32_MAX = 9;
- /// Creates an array of cached tasks for the values in the range [INCLUSIVE_MIN,EXCLUSIVE_MAX).
- private static Task[] CreateInt32Tasks()
- {
- Contract.Assert(EXCLUSIVE_INT32_MAX >= INCLUSIVE_INT32_MIN, "Expected max to be at least min");
- var tasks = new Task[EXCLUSIVE_INT32_MAX - INCLUSIVE_INT32_MIN];
- for (int i = 0; i < tasks.Length; i++)
- {
- tasks[i] = CreateCacheableTask(i + INCLUSIVE_INT32_MIN);
- }
- return tasks;
- }
-
- /// Creates a non-disposable task.
- /// Specifies the result type.
- /// The result for the task.
- /// The cacheable task.
- internal static Task CreateCacheableTask(TResult result)
- {
- return new Task(false, result, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));
- }
}
/// Holds state related to the builder's IAsyncStateMachine.
diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs
index 6031457c5b4a..f72166057f14 100644
--- a/src/mscorlib/src/System/Threading/Tasks/Task.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs
@@ -5521,7 +5521,7 @@ public static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationTok
/// The successfully completed task.
public static Task FromResult(TResult result)
{
- return new Task(result);
+ return Task.GetTaskForResult(result);
}
/// Creates a that's completed exceptionally with the specified exception.
diff --git a/src/mscorlib/src/System/Threading/Tasks/future.cs b/src/mscorlib/src/System/Threading/Tasks/future.cs
index 120782853e91..49171a9ad218 100644
--- a/src/mscorlib/src/System/Threading/Tasks/future.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/future.cs
@@ -1575,7 +1575,102 @@ ref stackMark
#endregion
#endregion
-
+
+ /// A cached task for default(TResult).
+ internal readonly static Task s_defaultResultTask = AsyncTaskCache.CreateCacheableTask(default(TResult));
+
+ ///
+ /// Gets a task for the specified result. This will either
+ /// be a cached or new task, never null.
+ ///
+ /// The result for which we need a task.
+ /// The completed task containing the result.
+ [SecuritySafeCritical] // for JitHelpers.UnsafeCast
+ internal static Task GetTaskForResult(TResult result)
+ {
+ Contract.Ensures(
+ EqualityComparer.Default.Equals(result, Contract.Result>().Result),
+ "The returned task's Result must return the same value as the specified result value.");
+
+ // The goal of this function is to be give back a cached task if possible,
+ // or to otherwise give back a new task. To give back a cached task,
+ // we need to be able to evaluate the incoming result value, and we need
+ // to avoid as much overhead as possible when doing so, as this function
+ // is invoked as part of the return path from every async method.
+ // Most tasks won't be cached, and thus we need the checks for those that are
+ // to be as close to free as possible. This requires some trickiness given the
+ // lack of generic specialization in .NET.
+ //
+ // Be very careful when modifying this code. It has been tuned
+ // to comply with patterns recognized by both 32-bit and 64-bit JITs.
+ // If changes are made here, be sure to look at the generated assembly, as
+ // small tweaks can have big consequences for what does and doesn't get optimized away.
+ //
+ // Note that this code only ever accesses a static field when it knows it'll
+ // find a cached value, since static fields (even if readonly and integral types)
+ // require special access helpers in this NGEN'd and domain-neutral.
+
+ if (null != (object)default(TResult)) // help the JIT avoid the value type branches for ref types
+ {
+ // Special case simple value types:
+ // - Boolean
+ // - Byte, SByte
+ // - Char
+ // - Decimal
+ // - Int32, UInt32
+ // - Int64, UInt64
+ // - Int16, UInt16
+ // - IntPtr, UIntPtr
+ // As of .NET 4.5, the (Type)(object)result pattern used below
+ // is recognized and optimized by both 32-bit and 64-bit JITs.
+
+ // For Boolean, we cache all possible values.
+ if (typeof(TResult) == typeof(Boolean)) // only the relevant branches are kept for each value-type generic instantiation
+ {
+ Boolean value = (Boolean)(object)result;
+ Task task = value ? AsyncTaskCache.TrueTask : AsyncTaskCache.FalseTask;
+ return JitHelpers.UnsafeCast>(task); // UnsafeCast avoids type check we know will succeed
+ }
+ // For Int32, we cache a range of common values, e.g. [-1,4).
+ else if (typeof(TResult) == typeof(Int32))
+ {
+ // Compare to constants to avoid static field access if outside of cached range.
+ // We compare to the upper bound first, as we're more likely to cache miss on the upper side than on the
+ // lower side, due to positive values being more common than negative as return values.
+ Int32 value = (Int32)(object)result;
+ if (value < AsyncTaskCache.EXCLUSIVE_INT32_MAX &&
+ value >= AsyncTaskCache.INCLUSIVE_INT32_MIN)
+ {
+ Task task = AsyncTaskCache.Int32Tasks[value - AsyncTaskCache.INCLUSIVE_INT32_MIN];
+ return JitHelpers.UnsafeCast>(task); // UnsafeCast avoids a type check we know will succeed
+ }
+ }
+ // For other known value types, we only special-case 0 / default(TResult).
+ else if (
+ (typeof(TResult) == typeof(UInt32) && default(UInt32) == (UInt32)(object)result) ||
+ (typeof(TResult) == typeof(Byte) && default(Byte) == (Byte)(object)result) ||
+ (typeof(TResult) == typeof(SByte) && default(SByte) == (SByte)(object)result) ||
+ (typeof(TResult) == typeof(Char) && default(Char) == (Char)(object)result) ||
+ (typeof(TResult) == typeof(Decimal) && default(Decimal) == (Decimal)(object)result) ||
+ (typeof(TResult) == typeof(Int64) && default(Int64) == (Int64)(object)result) ||
+ (typeof(TResult) == typeof(UInt64) && default(UInt64) == (UInt64)(object)result) ||
+ (typeof(TResult) == typeof(Int16) && default(Int16) == (Int16)(object)result) ||
+ (typeof(TResult) == typeof(UInt16) && default(UInt16) == (UInt16)(object)result) ||
+ (typeof(TResult) == typeof(IntPtr) && default(IntPtr) == (IntPtr)(object)result) ||
+ (typeof(TResult) == typeof(UIntPtr) && default(UIntPtr) == (UIntPtr)(object)result))
+ {
+ return s_defaultResultTask;
+ }
+ }
+ else if (result == null) // optimized away for value types
+ {
+ return s_defaultResultTask;
+ }
+
+ // No cached task is available. Manufacture a new one for this result.
+ return new Task(result);
+ }
+
///
/// Subscribes an to receive notification of the final state of this .
///
@@ -1618,6 +1713,44 @@ IDisposable IObservable.Subscribe(IObserver observer)
#endif
}
+ /// Provides a cache of closed generic tasks for async methods.
+ internal static class AsyncTaskCache
+ {
+ // All static members are initialized inline to ensure type is beforefieldinit
+
+ /// A cached Task{Boolean}.Result == true.
+ internal readonly static Task TrueTask = CreateCacheableTask(true);
+ /// A cached Task{Boolean}.Result == false.
+ internal readonly static Task FalseTask = CreateCacheableTask(false);
+
+ /// The cache of Task{Int32}.
+ internal readonly static Task[] Int32Tasks = CreateInt32Tasks();
+ /// The minimum value, inclusive, for which we want a cached task.
+ internal const Int32 INCLUSIVE_INT32_MIN = -1;
+ /// The maximum value, exclusive, for which we want a cached task.
+ internal const Int32 EXCLUSIVE_INT32_MAX = 9;
+ /// Creates an array of cached tasks for the values in the range [INCLUSIVE_MIN,EXCLUSIVE_MAX).
+ private static Task[] CreateInt32Tasks()
+ {
+ Contract.Assert(EXCLUSIVE_INT32_MAX >= INCLUSIVE_INT32_MIN, "Expected max to be at least min");
+ var tasks = new Task[EXCLUSIVE_INT32_MAX - INCLUSIVE_INT32_MIN];
+ for (int i = 0; i < tasks.Length; i++)
+ {
+ tasks[i] = CreateCacheableTask(i + INCLUSIVE_INT32_MIN);
+ }
+ return tasks;
+ }
+
+ /// Creates a non-disposable task.
+ /// Specifies the result type.
+ /// The result for the task.
+ /// The cacheable task.
+ internal static Task CreateCacheableTask(TResult result)
+ {
+ return new Task(false, result, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));
+ }
+ }
+
#if SUPPORT_IOBSERVABLE
// Class that calls RemoveContinuation if Dispose() is called before task completion
internal class DisposableSubscription : IDisposable
@@ -1644,8 +1777,8 @@ void IDisposable.Dispose()
}
#endif
- // Proxy class for better debugging experience
- internal class SystemThreadingTasks_FutureDebugView
+ // Proxy class for better debugging experience
+ internal class SystemThreadingTasks_FutureDebugView
{
private Task m_task;