Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 735b29c

Browse files
jkotassafern
authored andcommitted
Move types to shared corelib partition (dotnet/coreclr#15768)
- YieldAwaitable: Fixed readonly mismatch - Comparer: Made public to fix https://github.com/dotnet/corefx/issues/25973 Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
1 parent 197679e commit 735b29c

File tree

5 files changed

+253
-18
lines changed

5 files changed

+253
-18
lines changed

src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
<Compile Include="$(MSBuildThisFileDirectory)System\Char.cs" />
5555
<Compile Include="$(MSBuildThisFileDirectory)System\CharEnumerator.cs" />
5656
<Compile Include="$(MSBuildThisFileDirectory)System\CLSCompliantAttribute.cs" />
57+
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Comparer.cs" />
5758
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\DictionaryEntry.cs" />
5859
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\Dictionary.cs" />
5960
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\ICollection.cs" />
@@ -407,6 +408,7 @@
407408
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\TypeForwardedToAttribute.cs" />
408409
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\UnsafeValueTypeAttribute.cs" />
409410
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\ValueTaskAwaiter.cs" />
411+
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\YieldAwaitable.cs" />
410412
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\ConstrainedExecution\Cer.cs" />
411413
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\ConstrainedExecution\Consistency.cs" />
412414
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\ConstrainedExecution\ReliabilityContractAttribute.cs" />
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
/*============================================================
6+
**
7+
** Purpose: Default IComparer implementation.
8+
**
9+
===========================================================*/
10+
11+
using System.Globalization;
12+
using System.Runtime.Serialization;
13+
14+
namespace System.Collections
15+
{
16+
[Serializable]
17+
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
18+
public sealed class Comparer : IComparer, ISerializable
19+
{
20+
private CompareInfo _compareInfo;
21+
22+
public static readonly Comparer Default = new Comparer(CultureInfo.CurrentCulture);
23+
public static readonly Comparer DefaultInvariant = new Comparer(CultureInfo.InvariantCulture);
24+
25+
public Comparer(CultureInfo culture)
26+
{
27+
if (culture == null)
28+
throw new ArgumentNullException(nameof(culture));
29+
30+
_compareInfo = culture.CompareInfo;
31+
}
32+
33+
private Comparer(SerializationInfo info, StreamingContext context)
34+
{
35+
if (info == null)
36+
throw new ArgumentNullException(nameof(info));
37+
38+
_compareInfo = (CompareInfo)info.GetValue("CompareInfo", typeof(CompareInfo));
39+
}
40+
41+
public void GetObjectData(SerializationInfo info, StreamingContext context)
42+
{
43+
if (info == null)
44+
throw new ArgumentNullException(nameof(info));
45+
46+
info.AddValue("CompareInfo", _compareInfo);
47+
}
48+
49+
// Compares two Objects by calling CompareTo.
50+
// If a == b, 0 is returned.
51+
// If a implements IComparable, a.CompareTo(b) is returned.
52+
// If a doesn't implement IComparable and b does, -(b.CompareTo(a)) is returned.
53+
// Otherwise an exception is thrown.
54+
//
55+
public int Compare(Object a, Object b)
56+
{
57+
if (a == b) return 0;
58+
if (a == null) return -1;
59+
if (b == null) return 1;
60+
61+
string sa = a as string;
62+
string sb = b as string;
63+
if (sa != null && sb != null)
64+
return _compareInfo.Compare(sa, sb);
65+
66+
IComparable ia = a as IComparable;
67+
if (ia != null)
68+
return ia.CompareTo(b);
69+
70+
IComparable ib = b as IComparable;
71+
if (ib != null)
72+
return -ib.CompareTo(a);
73+
74+
throw new ArgumentException(SR.Argument_ImplementIComparable);
75+
}
76+
}
77+
}

src/Common/src/CoreLib/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ namespace System.Collections.Generic
1111
// keeps the performance not affected till we hit collision threshold and then we switch to the comparer which is using
1212
// randomized string hashing.
1313
[Serializable] // Required for compatibility with .NET Core 2.0 as we exposed the NonRandomizedStringEqualityComparer inside the serialization blob
14-
#if CORECLR
15-
internal
16-
#else
14+
#if CORERT
1715
public
16+
#else
17+
internal
1818
#endif
1919
sealed class NonRandomizedStringEqualityComparer : EqualityComparer<string>, ISerializable
2020
{

src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfoScanner.cs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,6 @@
2424

2525
namespace System.Globalization
2626
{
27-
#if CORECLR
28-
using StringStringDictionary = Dictionary<string, string>;
29-
using StringList = List<string>;
30-
#else
31-
using StringStringDictionary = LowLevelDictionary<string, string>;
32-
using StringList = LowLevelList<string>;
33-
#endif
34-
3527
//
3628
// from LocaleEx.txt header
3729
//
@@ -121,17 +113,17 @@ internal class DateTimeFormatInfoScanner
121113
internal const String CJKSecondSuff = "\u79d2";
122114

123115
// The collection fo date words & postfix.
124-
internal StringList m_dateWords = new StringList();
116+
internal List<string> m_dateWords = new List<string>();
125117
// Hashtable for the known words.
126-
private static volatile StringStringDictionary s_knownWords;
118+
private static volatile Dictionary<string, string> s_knownWords;
127119

128-
static StringStringDictionary KnownWords
120+
static Dictionary<string, string> KnownWords
129121
{
130122
get
131123
{
132124
if (s_knownWords == null)
133125
{
134-
StringStringDictionary temp = new StringStringDictionary();
126+
Dictionary<string, string> temp = new Dictionary<string, string>();
135127
// Add known words into the hash table.
136128

137129
// Skip these special symbols.
@@ -234,7 +226,7 @@ internal void AddDateWordOrPostfix(String formatPostfix, String str)
234226
{
235227
if (m_dateWords == null)
236228
{
237-
m_dateWords = new StringList();
229+
m_dateWords = new List<string>();
238230
}
239231
if (formatPostfix == "MMMM")
240232
{
@@ -380,7 +372,7 @@ internal void AddIgnorableSymbols(String text)
380372
if (m_dateWords == null)
381373
{
382374
// Create the date word array.
383-
m_dateWords = new StringList();
375+
m_dateWords = new List<string>();
384376
}
385377
// Add the ignorable symbol into the ArrayList.
386378
String temp = IgnorableSymbolChar + text;
@@ -735,4 +727,3 @@ private static bool ArrayElementsBeginWithDigit(string[] array)
735727
}
736728
}
737729
}
738-
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
6+
//
7+
//
8+
//
9+
// Compiler-targeted type for switching back into the current execution context, e.g.
10+
//
11+
// await Task.Yield();
12+
// =====================
13+
// var $awaiter = Task.Yield().GetAwaiter();
14+
// if (!$awaiter.IsCompleted)
15+
// {
16+
// $builder.AwaitUnsafeOnCompleted(ref $awaiter, ref this);
17+
// return;
18+
// Label:
19+
// }
20+
// $awaiter.GetResult();
21+
//
22+
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
23+
24+
using System;
25+
using System.Security;
26+
using System.Diagnostics;
27+
using System.Diagnostics.Tracing;
28+
using System.Threading;
29+
using System.Threading.Tasks;
30+
31+
namespace System.Runtime.CompilerServices
32+
{
33+
// NOTE: YieldAwaitable currently has no state; while developers are encouraged to use Task.Yield() to produce one,
34+
// no validation is performed to ensure that the developer isn't doing "await new YieldAwaitable()". Such validation
35+
// would require additional, useless state to be stored, and as this is a type in the CompilerServices namespace, and
36+
// as the above example isn't harmful, we take the cheaper approach of not validating anything.
37+
38+
/// <summary>Provides an awaitable context for switching into a target environment.</summary>
39+
/// <remarks>This type is intended for compiler use only.</remarks>
40+
public readonly struct YieldAwaitable
41+
{
42+
/// <summary>Gets an awaiter for this <see cref="YieldAwaitable"/>.</summary>
43+
/// <returns>An awaiter for this awaitable.</returns>
44+
/// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
45+
public YieldAwaiter GetAwaiter() { return new YieldAwaiter(); }
46+
47+
/// <summary>Provides an awaiter that switches into a target environment.</summary>
48+
/// <remarks>This type is intended for compiler use only.</remarks>
49+
public readonly struct YieldAwaiter : ICriticalNotifyCompletion
50+
{
51+
/// <summary>Gets whether a yield is not required.</summary>
52+
/// <remarks>This property is intended for compiler user rather than use directly in code.</remarks>
53+
public bool IsCompleted { get { return false; } } // yielding is always required for YieldAwaiter, hence false
54+
55+
/// <summary>Posts the <paramref name="continuation"/> back to the current context.</summary>
56+
/// <param name="continuation">The action to invoke asynchronously.</param>
57+
/// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
58+
public void OnCompleted(Action continuation)
59+
{
60+
QueueContinuation(continuation, flowContext: true);
61+
}
62+
63+
/// <summary>Posts the <paramref name="continuation"/> back to the current context.</summary>
64+
/// <param name="continuation">The action to invoke asynchronously.</param>
65+
/// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
66+
public void UnsafeOnCompleted(Action continuation)
67+
{
68+
QueueContinuation(continuation, flowContext: false);
69+
}
70+
71+
/// <summary>Posts the <paramref name="continuation"/> back to the current context.</summary>
72+
/// <param name="continuation">The action to invoke asynchronously.</param>
73+
/// <param name="flowContext">true to flow ExecutionContext; false if flowing is not required.</param>
74+
/// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
75+
private static void QueueContinuation(Action continuation, bool flowContext)
76+
{
77+
// Validate arguments
78+
if (continuation == null) throw new ArgumentNullException(nameof(continuation));
79+
80+
if (TplEtwProvider.Log.IsEnabled())
81+
{
82+
continuation = OutputCorrelationEtwEvent(continuation);
83+
}
84+
// Get the current SynchronizationContext, and if there is one,
85+
// post the continuation to it. However, treat the base type
86+
// as if there wasn't a SynchronizationContext, since that's what it
87+
// logically represents.
88+
var syncCtx = SynchronizationContext.Current;
89+
if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
90+
{
91+
syncCtx.Post(s_sendOrPostCallbackRunAction, continuation);
92+
}
93+
else
94+
{
95+
// If we're targeting the default scheduler, queue to the thread pool, so that we go into the global
96+
// queue. As we're going into the global queue, we might as well use QUWI, which for the global queue is
97+
// just a tad faster than task, due to a smaller object getting allocated and less work on the execution path.
98+
TaskScheduler scheduler = TaskScheduler.Current;
99+
if (scheduler == TaskScheduler.Default)
100+
{
101+
if (flowContext)
102+
{
103+
ThreadPool.QueueUserWorkItem(s_waitCallbackRunAction, continuation);
104+
}
105+
else
106+
{
107+
ThreadPool.UnsafeQueueUserWorkItem(s_waitCallbackRunAction, continuation);
108+
}
109+
}
110+
// We're targeting a custom scheduler, so queue a task.
111+
else
112+
{
113+
Task.Factory.StartNew(continuation, default(CancellationToken), TaskCreationOptions.PreferFairness, scheduler);
114+
}
115+
}
116+
}
117+
118+
private static Action OutputCorrelationEtwEvent(Action continuation)
119+
{
120+
#if CORERT
121+
// TODO
122+
return continuation;
123+
#else
124+
int continuationId = Task.NewId();
125+
Task currentTask = Task.InternalCurrent;
126+
// fire the correlation ETW event
127+
TplEtwProvider.Log.AwaitTaskContinuationScheduled(TaskScheduler.Current.Id, (currentTask != null) ? currentTask.Id : 0, continuationId);
128+
129+
return AsyncMethodBuilderCore.CreateContinuationWrapper(continuation, (innerContinuation,continuationIdTask) =>
130+
{
131+
var etwLog = TplEtwProvider.Log;
132+
etwLog.TaskWaitContinuationStarted(((Task<int>)continuationIdTask).Result);
133+
134+
// ETW event for Task Wait End.
135+
Guid prevActivityId = new Guid();
136+
// Ensure the continuation runs under the correlated activity ID generated above
137+
if (etwLog.TasksSetActivityIds)
138+
EventSource.SetCurrentThreadActivityId(TplEtwProvider.CreateGuidForTaskID(((Task<int>)continuationIdTask).Result), out prevActivityId);
139+
140+
// Invoke the original continuation provided to OnCompleted.
141+
innerContinuation();
142+
// Restore activity ID
143+
144+
if (etwLog.TasksSetActivityIds)
145+
EventSource.SetCurrentThreadActivityId(prevActivityId);
146+
147+
etwLog.TaskWaitContinuationComplete(((Task<int>)continuationIdTask).Result);
148+
}, Task.FromResult(continuationId)); // pass the ID in a task to avoid a closure\
149+
#endif
150+
}
151+
152+
/// <summary>WaitCallback that invokes the Action supplied as object state.</summary>
153+
private static readonly WaitCallback s_waitCallbackRunAction = RunAction;
154+
/// <summary>SendOrPostCallback that invokes the Action supplied as object state.</summary>
155+
private static readonly SendOrPostCallback s_sendOrPostCallbackRunAction = RunAction;
156+
157+
/// <summary>Runs an Action delegate provided as state.</summary>
158+
/// <param name="state">The Action delegate to invoke.</param>
159+
private static void RunAction(object state) { ((Action)state)(); }
160+
161+
/// <summary>Ends the await operation.</summary>
162+
public void GetResult() { } // Nop. It exists purely because the compiler pattern demands it.
163+
}
164+
}
165+
}

0 commit comments

Comments
 (0)