From 5b975f8233e8c8d17b215372f89ca713b45d6a0b Mon Sep 17 00:00:00 2001 From: Jiyoung Yun Date: Thu, 27 Apr 2017 16:54:50 +0900 Subject: Imported Upstream version 2.0.0.11599 --- .../src/System/Collections/Generic/Dictionary.cs | 89 +- .../src/System/Collections/Generic/List.cs | 1 + src/mscorlib/src/System/Delegate.cs | 5 +- src/mscorlib/src/System/Environment.cs | 2 +- .../src/System/Globalization/CompareInfo.cs | 48 +- .../System/Globalization/HijriCalendar.Win32.cs | 61 +- .../System/Globalization/JapaneseCalendar.Win32.cs | 38 +- src/mscorlib/src/System/IO/Stream.cs | 4 +- src/mscorlib/src/System/ReadOnlySpan.cs | 313 ------- .../src/System/Reflection/Assembly.CoreCLR.cs | 24 +- .../System/Runtime/CompilerServices/TaskAwaiter.cs | 2 +- .../System/Runtime/CompilerServices/jithelpers.cs | 9 +- .../src/System/Runtime/InteropServices/Marshal.cs | 3 + src/mscorlib/src/System/Span.cs | 910 --------------------- src/mscorlib/src/System/String.Manipulation.cs | 7 +- src/mscorlib/src/System/String.cs | 2 +- src/mscorlib/src/System/Threading/Tasks/Task.cs | 3 +- .../src/System/Threading/Tasks/TaskContinuation.cs | 2 +- src/mscorlib/src/System/Threading/Tasks/future.cs | 6 +- src/mscorlib/src/System/ThrowHelper.cs | 1 + src/mscorlib/src/System/TimeZoneInfo.Win32.cs | 30 +- src/mscorlib/src/System/TimeZoneInfo.cs | 114 ++- 22 files changed, 297 insertions(+), 1377 deletions(-) delete mode 100644 src/mscorlib/src/System/ReadOnlySpan.cs delete mode 100644 src/mscorlib/src/System/Span.cs (limited to 'src/mscorlib/src/System') diff --git a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs b/src/mscorlib/src/System/Collections/Generic/Dictionary.cs index 409b23b541..e360eef897 100644 --- a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs +++ b/src/mscorlib/src/System/Collections/Generic/Dictionary.cs @@ -48,6 +48,7 @@ namespace System.Collections.Generic using System.Collections; using System.Diagnostics; using System.Diagnostics.Contracts; + using System.Runtime.CompilerServices; using System.Runtime.Serialization; /// @@ -428,8 +429,7 @@ namespace System.Collections.Generic if (buckets == null) Initialize(0); int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; - int targetBucket = hashCode % buckets.Length; - + int targetBucket = hashCode % buckets.Length; #if FEATURE_RANDOMIZED_STRING_HASHING int collisionCount = 0; #endif @@ -452,7 +452,6 @@ namespace System.Collections.Generic return false; } - #if FEATURE_RANDOMIZED_STRING_HASHING collisionCount++; #endif @@ -599,27 +598,40 @@ namespace System.Collections.Generic int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; int bucket = hashCode % buckets.Length; int last = -1; - for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next) + int i = buckets[bucket]; + while (i >= 0) { - if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) + ref Entry entry = ref entries[i]; + + if (entry.hashCode == hashCode && comparer.Equals(entry.key, key)) { if (last < 0) { - buckets[bucket] = entries[i].next; + buckets[bucket] = entry.next; } else { - entries[last].next = entries[i].next; + entries[last].next = entry.next; + } + entry.hashCode = -1; + entry.next = freeList; + + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + { + entry.key = default(TKey); + } + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + { + entry.value = default(TValue); } - entries[i].hashCode = -1; - entries[i].next = freeList; - entries[i].key = default(TKey); - entries[i].value = default(TValue); freeList = i; freeCount++; version++; return true; } + + last = i; + i = entry.next; } } return false; @@ -640,30 +652,43 @@ namespace System.Collections.Generic int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; int bucket = hashCode % buckets.Length; int last = -1; - for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next) + int i = buckets[bucket]; + while (i >= 0) { - if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) + ref Entry entry = ref entries[i]; + + if (entry.hashCode == hashCode && comparer.Equals(entry.key, key)) { if (last < 0) { - buckets[bucket] = entries[i].next; + buckets[bucket] = entry.next; } else { - entries[last].next = entries[i].next; + entries[last].next = entry.next; } - value = entries[i].value; + value = entry.value; - entries[i].hashCode = -1; - entries[i].next = freeList; - entries[i].key = default(TKey); - entries[i].value = default(TValue); + entry.hashCode = -1; + entry.next = freeList; + + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + { + entry.key = default(TKey); + } + if (RuntimeHelpers.IsReferenceOrContainsReferences()) + { + entry.value = default(TValue); + } freeList = i; freeCount++; version++; return true; } + + last = i; + i = entry.next; } } value = default(TValue); @@ -955,13 +980,13 @@ namespace System.Collections.Generic // dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue while ((uint)index < (uint)dictionary.count) { - if (dictionary.entries[index].hashCode >= 0) + ref Entry entry = ref dictionary.entries[index++]; + + if (entry.hashCode >= 0) { - current = new KeyValuePair(dictionary.entries[index].key, dictionary.entries[index].value); - index++; + current = new KeyValuePair(entry.key, entry.value); return true; } - index++; } index = dictionary.count + 1; @@ -1231,13 +1256,13 @@ namespace System.Collections.Generic while ((uint)index < (uint)dictionary.count) { - if (dictionary.entries[index].hashCode >= 0) + ref Entry entry = ref dictionary.entries[index++]; + + if (entry.hashCode >= 0) { - currentKey = dictionary.entries[index].key; - index++; + currentKey = entry.key; return true; } - index++; } index = dictionary.count + 1; @@ -1459,13 +1484,13 @@ namespace System.Collections.Generic while ((uint)index < (uint)dictionary.count) { - if (dictionary.entries[index].hashCode >= 0) + ref Entry entry = ref dictionary.entries[index++]; + + if (entry.hashCode >= 0) { - currentValue = dictionary.entries[index].value; - index++; + currentValue = entry.value; return true; } - index++; } index = dictionary.count + 1; currentValue = default(TValue); diff --git a/src/mscorlib/src/System/Collections/Generic/List.cs b/src/mscorlib/src/System/Collections/Generic/List.cs index 67d1668aad..4e480885ef 100644 --- a/src/mscorlib/src/System/Collections/Generic/List.cs +++ b/src/mscorlib/src/System/Collections/Generic/List.cs @@ -350,6 +350,7 @@ namespace System.Collections.Generic // Clears the contents of List. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() { if (RuntimeHelpers.IsReferenceOrContainsReferences()) diff --git a/src/mscorlib/src/System/Delegate.cs b/src/mscorlib/src/System/Delegate.cs index de0ff6532c..75ec57a003 100644 --- a/src/mscorlib/src/System/Delegate.cs +++ b/src/mscorlib/src/System/Delegate.cs @@ -179,7 +179,10 @@ namespace System else return unchecked((int)((long)this._methodPtrAux)); */ - return GetType().GetHashCode(); + if (_methodPtrAux.IsNull()) + return ( _target != null ? RuntimeHelpers.GetHashCode(_target) * 33 : 0) + GetType().GetHashCode(); + else + return GetType().GetHashCode(); } public static Delegate Combine(Delegate a, Delegate b) diff --git a/src/mscorlib/src/System/Environment.cs b/src/mscorlib/src/System/Environment.cs index b9070ae713..dddbdc242d 100644 --- a/src/mscorlib/src/System/Environment.cs +++ b/src/mscorlib/src/System/Environment.cs @@ -820,7 +820,7 @@ namespace System } else { - environmentKey.SetStringValue(variable, value); + environmentKey.SetValue(variable, value); } } } diff --git a/src/mscorlib/src/System/Globalization/CompareInfo.cs b/src/mscorlib/src/System/Globalization/CompareInfo.cs index 285a81d906..b2c2208db7 100644 --- a/src/mscorlib/src/System/Globalization/CompareInfo.cs +++ b/src/mscorlib/src/System/Globalization/CompareInfo.cs @@ -752,7 +752,6 @@ namespace System.Globalization return IndexOfCore(source, new string(value, 1), startIndex, count, options, null); } - public unsafe virtual int IndexOf(string source, string value, int startIndex, int count, CompareOptions options) { // Validate inputs @@ -802,6 +801,53 @@ namespace System.Globalization return IndexOfCore(source, value, startIndex, count, options, null); } + // The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated + // and the caller is passing a valid matchLengthPtr pointer. + internal unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options, int* matchLengthPtr) + { + Debug.Assert(source != null); + Debug.Assert(value != null); + Debug.Assert(startIndex >= 0); + Debug.Assert(matchLengthPtr != null); + *matchLengthPtr = 0; + + if (source.Length == 0) + { + if (value.Length == 0) + { + return 0; + } + return -1; + } + + if (startIndex >= source.Length) + { + return -1; + } + + if (options == CompareOptions.OrdinalIgnoreCase) + { + int res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); + if (res >= 0) + { + *matchLengthPtr = value.Length; + } + return res; + } + + if (_invariantMode) + { + int res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase: (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0); + if (res >= 0) + { + *matchLengthPtr = value.Length; + } + return res; + } + + return IndexOfCore(source, value, startIndex, count, options, matchLengthPtr); + } + internal int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) { if (_invariantMode) diff --git a/src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs b/src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs index 4ba95c8fa8..869b809bff 100644 --- a/src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs +++ b/src/mscorlib/src/System/Globalization/HijriCalendar.Win32.cs @@ -42,41 +42,54 @@ namespace System.Globalization int hijriAdvance = 0; Microsoft.Win32.RegistryKey key = null; - using (key = Registry.CurrentUser.OpenSubKey(InternationalRegKey, writable: false)) + try { - if (key == null) - return 0; + // Open in read-only mode. + // Use InternalOpenSubKey so that we avoid the security check. + key = RegistryKey.GetBaseKey(RegistryKey.HKEY_CURRENT_USER).OpenSubKey(InternationalRegKey, false); + } + //If this fails for any reason, we'll just return 0. + catch (ObjectDisposedException) { return 0; } + catch (ArgumentException) { return 0; } - Object value = key.GetValue(HijriAdvanceRegKeyEntry); - if (value == null) - { - return (0); - } - String str = value.ToString(); - if (String.Compare(str, 0, HijriAdvanceRegKeyEntry, 0, HijriAdvanceRegKeyEntry.Length, StringComparison.OrdinalIgnoreCase) == 0) + if (key != null) + { + try { - if (str.Length == HijriAdvanceRegKeyEntry.Length) - hijriAdvance = -1; - else + Object value = key.InternalGetValue(HijriAdvanceRegKeyEntry, null, false, false); + if (value == null) { - str = str.Substring(HijriAdvanceRegKeyEntry.Length); - try + return (0); + } + String str = value.ToString(); + if (String.Compare(str, 0, HijriAdvanceRegKeyEntry, 0, HijriAdvanceRegKeyEntry.Length, StringComparison.OrdinalIgnoreCase) == 0) + { + if (str.Length == HijriAdvanceRegKeyEntry.Length) + hijriAdvance = -1; + else { - int advance = Int32.Parse(str.ToString(), CultureInfo.InvariantCulture); - if ((advance >= MinAdvancedHijri) && (advance <= MaxAdvancedHijri)) + str = str.Substring(HijriAdvanceRegKeyEntry.Length); + try { - hijriAdvance = advance; + int advance = Int32.Parse(str.ToString(), CultureInfo.InvariantCulture); + if ((advance >= MinAdvancedHijri) && (advance <= MaxAdvancedHijri)) + { + hijriAdvance = advance; + } } + // If we got garbage from registry just ignore it. + // hijriAdvance = 0 because of declaraction assignment up above. + catch (ArgumentException) { } + catch (FormatException) { } + catch (OverflowException) { } } - // If we got garbage from registry just ignore it. - // hijriAdvance = 0 because of declaraction assignment up above. - catch (ArgumentException) { } - catch (FormatException) { } - catch (OverflowException) { } } } + finally + { + key.Close(); + } } - return (hijriAdvance); } } diff --git a/src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs b/src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs index fe8b1b5896..a83c4fad9e 100644 --- a/src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs +++ b/src/mscorlib/src/System/Globalization/JapaneseCalendar.Win32.cs @@ -36,30 +36,30 @@ namespace System.Globalization try { - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(c_japaneseErasHive, writable: false)) + // Need to access registry + RegistryKey key = RegistryKey.GetBaseKey(RegistryKey.HKEY_LOCAL_MACHINE).OpenSubKey(c_japaneseErasHive, false); + + // Abort if we didn't find anything + if (key == null) return null; + + // Look up the values in our reg key + String[] valueNames = key.GetValueNames(); + if (valueNames != null && valueNames.Length > 0) { - // Abort if we didn't find anything - if (key == null) return null; + registryEraRanges = new EraInfo[valueNames.Length]; - // Look up the values in our reg key - String[] valueNames = key.GetValueNames(); - if (valueNames != null && valueNames.Length > 0) + // Loop through the registry and read in all the values + for (int i = 0; i < valueNames.Length; i++) { - registryEraRanges = new EraInfo[valueNames.Length]; - - // Loop through the registry and read in all the values - for (int i = 0; i < valueNames.Length; i++) - { - // See if the era is a valid date - EraInfo era = GetEraFromValue(valueNames[i], key.GetValue(valueNames[i]).ToString()); + // See if the era is a valid date + EraInfo era = GetEraFromValue(valueNames[i], key.GetValue(valueNames[i]).ToString()); - // continue if not valid - if (era == null) continue; + // continue if not valid + if (era == null) continue; - // Remember we found one. - registryEraRanges[iFoundEras] = era; - iFoundEras++; - } + // Remember we found one. + registryEraRanges[iFoundEras] = era; + iFoundEras++; } } } diff --git a/src/mscorlib/src/System/IO/Stream.cs b/src/mscorlib/src/System/IO/Stream.cs index 92fe374f19..65cc4ddcb9 100644 --- a/src/mscorlib/src/System/IO/Stream.cs +++ b/src/mscorlib/src/System/IO/Stream.cs @@ -522,14 +522,14 @@ namespace System.IO // If the wait has already completed, run the task. if (asyncWaiter.IsCompleted) { - Debug.Assert(asyncWaiter.IsRanToCompletion, "The semaphore wait should always complete successfully."); + Debug.Assert(asyncWaiter.IsCompletedSuccessfully, "The semaphore wait should always complete successfully."); RunReadWriteTask(readWriteTask); } else // Otherwise, wait for our turn, and then run the task. { asyncWaiter.ContinueWith((t, state) => { - Debug.Assert(t.IsRanToCompletion, "The semaphore wait should always complete successfully."); + Debug.Assert(t.IsCompletedSuccessfully, "The semaphore wait should always complete successfully."); var rwt = (ReadWriteTask)state; rwt._stream.RunReadWriteTask(rwt); // RunReadWriteTask(readWriteTask); }, readWriteTask, default(CancellationToken), TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); diff --git a/src/mscorlib/src/System/ReadOnlySpan.cs b/src/mscorlib/src/System/ReadOnlySpan.cs deleted file mode 100644 index 8d0fbad0fc..0000000000 --- a/src/mscorlib/src/System/ReadOnlySpan.cs +++ /dev/null @@ -1,313 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Runtime.CompilerServices; -using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; -using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; - -#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' - -namespace System -{ - /// - /// ReadOnlySpan represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed - /// or native memory, or to memory allocated on the stack. It is type- and memory-safe. - /// - public struct ReadOnlySpan - { - /// A byref or a native ptr. - private readonly ByReference _pointer; - /// The number of elements this ReadOnlySpan contains. - private readonly int _length; - - /// - /// Creates a new read-only span over the entirety of the target array. - /// - /// The target array. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan(T[] array) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - - _pointer = new ByReference(ref JitHelpers.GetArrayData(array)); - _length = array.Length; - } - - /// - /// Creates a new read-only span over the portion of the target array beginning - /// at 'start' index and covering the remainder of the array. - /// - /// The target array. - /// The index at which to begin the read-only span. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - /// - /// Thrown when the specified is not in the range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan(T[] array, int start) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if ((uint)start > (uint)array.Length) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start)); - _length = array.Length - start; - } - - /// - /// Creates a new read-only span over the portion of the target array beginning - /// at 'start' index and ending at 'end' index (exclusive). - /// - /// The target array. - /// The index at which to begin the read-only span. - /// The number of items in the read-only span. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - /// - /// Thrown when the specified or end index is not in the range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan(T[] array, int start, int length) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start)); - _length = length; - } - - /// - /// Creates a new read-only span over the target unmanaged buffer. Clearly this - /// is quite dangerous, because we are creating arbitrarily typed T's - /// out of a void*-typed block of memory. And the length is not checked. - /// But if this creation is correct, then all subsequent uses are correct. - /// - /// An unmanaged pointer to memory. - /// The number of elements the memory contains. - /// - /// Thrown when is reference type or contains pointers and hence cannot be stored in unmanaged memory. - /// - /// - /// Thrown when the specified is negative. - /// - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe ReadOnlySpan(void* pointer, int length) - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); - if (length < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.As(ref *(byte*)pointer)); - _length = length; - } - - /// - /// Create a new read-only span over a portion of a regular managed object. This can be useful - /// if part of a managed object represents a "fixed array." This is dangerous because neither the - /// is checked, nor being null, nor the fact that - /// "rawPointer" actually lies within . - /// - /// The managed object that contains the data to span over. - /// A reference to data within that object. - /// The number of elements the memory contains. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan DangerousCreate(object obj, ref T objectData, int length) => new ReadOnlySpan(ref objectData, length); - - // Constructor for internal use only. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ReadOnlySpan(ref T ptr, int length) - { - Debug.Assert(length >= 0); - - _pointer = new ByReference(ref ptr); - _length = length; - } - - /// - /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element - /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T DangerousGetPinnableReference() - { - return ref _pointer.Value; - } - - /// - /// The number of items in the read-only span. - /// - public int Length => _length; - - /// - /// Returns true if Length is 0. - /// - public bool IsEmpty => _length == 0; - - /// - /// Returns the specified element of the read-only span. - /// - /// - /// - /// - /// Thrown when index less than 0 or index greater than or equal to Length - /// - public T this[int index] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - if ((uint)index >= (uint)_length) - ThrowHelper.ThrowIndexOutOfRangeException(); - - return Unsafe.Add(ref _pointer.Value, index); - } - } - - /// - /// Copies the contents of this read-only span into destination span. If the source - /// and destinations overlap, this method behaves as if the original values in - /// a temporary location before the destination is overwritten. - /// - /// The span to copy items into. - /// - /// Thrown when the destination Span is shorter than the source Span. - /// - /// - public void CopyTo(Span destination) - { - if (!TryCopyTo(destination)) - ThrowHelper.ThrowArgumentException_DestinationTooShort(); - } - - /// Copies the contents of this read-only span into destination span. If the source - /// and destinations overlap, this method behaves as if the original values in - /// a temporary location before the destination is overwritten. - /// - /// If the destination span is shorter than the source span, this method - /// return false and no data is written to the destination. - /// The span to copy items into. - public bool TryCopyTo(Span destination) - { - if ((uint)_length > (uint)destination.Length) - return false; - - SpanHelper.CopyTo(ref destination.DangerousGetPinnableReference(), ref _pointer.Value, _length); - return true; - } - - /// - /// Returns true if left and right point at the same memory and have the same length. Note that - /// this does *not* check to see if the *contents* are equal. - /// - public static bool operator ==(ReadOnlySpan left, ReadOnlySpan right) - { - return left._length == right._length && Unsafe.AreSame(ref left._pointer.Value, ref right._pointer.Value); - } - - /// - /// Returns false if left and right point at the same memory and have the same length. Note that - /// this does *not* check to see if the *contents* are equal. - /// - public static bool operator !=(ReadOnlySpan left, ReadOnlySpan right) => !(left == right); - - /// - /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==. - /// - /// Always thrown by this method. - /// - /// - [Obsolete("Equals() on Span will always throw an exception. Use == instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool Equals(object obj) - { - throw new NotSupportedException(SR.NotSupported_CannotCallEqualsOnSpan); - } - - /// - /// This method is not supported as spans cannot be boxed. - /// - /// Always thrown by this method. - /// - /// - [Obsolete("GetHashCode() on Span will always throw an exception.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public override int GetHashCode() - { - throw new NotSupportedException(SR.NotSupported_CannotCallGetHashCodeOnSpan); - } - - /// - /// Defines an implicit conversion of an array to a - /// - public static implicit operator ReadOnlySpan(T[] array) => new ReadOnlySpan(array); - - /// - /// Defines an implicit conversion of a to a - /// - public static implicit operator ReadOnlySpan(ArraySegment arraySegment) => new ReadOnlySpan(arraySegment.Array, arraySegment.Offset, arraySegment.Count); - - /// - /// Forms a slice out of the given read-only span, beginning at 'start'. - /// - /// The index at which to begin this slice. - /// - /// Thrown when the specified index is not in range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan Slice(int start) - { - if ((uint)start > (uint)_length) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new ReadOnlySpan(ref Unsafe.Add(ref _pointer.Value, start), _length - start); - } - - /// - /// Forms a slice out of the given read-only span, beginning at 'start', of given length - /// - /// The index at which to begin this slice. - /// The desired length for the slice (exclusive). - /// - /// Thrown when the specified or end index is not in range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan Slice(int start, int length) - { - if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new ReadOnlySpan(ref Unsafe.Add(ref _pointer.Value, start), length); - } - - /// - /// Copies the contents of this read-only span into a new array. This heap - /// allocates, so should generally be avoided, however it is sometimes - /// necessary to bridge the gap with APIs written in terms of arrays. - /// - public T[] ToArray() - { - if (_length == 0) - return Array.Empty(); - - var destination = new T[_length]; - SpanHelper.CopyTo(ref JitHelpers.GetArrayData(destination), ref _pointer.Value, _length); - return destination; - } - - /// - /// Returns a 0-length read-only span whose base is the null pointer. - /// - public static ReadOnlySpan Empty => default(ReadOnlySpan); - } -} diff --git a/src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs b/src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs index 82966dba60..708f79b64f 100644 --- a/src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs +++ b/src/mscorlib/src/System/Reflection/Assembly.CoreCLR.cs @@ -101,14 +101,20 @@ namespace System.Reflection { Contract.Ensures(Contract.Result() != null); Contract.Ensures(!Contract.Result().ReflectionOnly); - + + AssemblyName modifiedAssemblyRef = null; if (assemblyRef != null && assemblyRef.CodeBase != null) { - throw new NotSupportedException(SR.NotSupported_AssemblyLoadCodeBase); + modifiedAssemblyRef = (AssemblyName)assemblyRef.Clone(); + modifiedAssemblyRef.CodeBase = null; } - + else + { + modifiedAssemblyRef = assemblyRef; + } + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return RuntimeAssembly.InternalLoadAssemblyName(assemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/); + return RuntimeAssembly.InternalLoadAssemblyName(modifiedAssemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/); } // Locate an assembly by its name. The name can be strong or @@ -119,13 +125,19 @@ namespace System.Reflection Contract.Ensures(Contract.Result() != null); Contract.Ensures(!Contract.Result().ReflectionOnly); + AssemblyName modifiedAssemblyRef = null; if (assemblyRef != null && assemblyRef.CodeBase != null) { - throw new NotSupportedException(SR.NotSupported_AssemblyLoadCodeBase); + modifiedAssemblyRef = (AssemblyName)assemblyRef.Clone(); + modifiedAssemblyRef.CodeBase = null; + } + else + { + modifiedAssemblyRef = assemblyRef; } StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return RuntimeAssembly.InternalLoadAssemblyName(assemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/, ptrLoadContextBinder); + return RuntimeAssembly.InternalLoadAssemblyName(modifiedAssemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/, ptrLoadContextBinder); } // Loads the assembly with a COFF based IMAGE containing diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs index e2fa6caa2d..c35658e54c 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs @@ -146,7 +146,7 @@ namespace System.Runtime.CompilerServices task.NotifyDebuggerOfWaitCompletionIfNecessary(); // And throw an exception if the task is faulted or canceled. - if (!task.IsRanToCompletion) ThrowForNonSuccess(task); + if (!task.IsCompletedSuccessfully) ThrowForNonSuccess(task); } /// Throws an exception to handle a task that completed in a state other than RanToCompletion. diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs index b86835f778..d5201350ec 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs @@ -216,14 +216,7 @@ namespace System.Runtime.CompilerServices private extern static bool IsAddressInStack(IntPtr ptr); #endif - static internal bool ByRefLessThan(ref T refA, ref T refB) - { - // The body of this function will be replaced by the EE with unsafe code!!! - // See getILIntrinsicImplementation for how this happens. - throw new InvalidOperationException(); - } - - static internal ref T GetArrayData(T[] array) + static internal ref byte GetRawSzArrayData(this Array array) { // The body of this function will be replaced by the EE with unsafe code!!! // See getILIntrinsicImplementation for how this happens. diff --git a/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs b/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs index 248e0d5778..6fb631121b 100644 --- a/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs +++ b/src/mscorlib/src/System/Runtime/InteropServices/Marshal.cs @@ -823,6 +823,9 @@ namespace System.Runtime.InteropServices } } + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public static extern /* struct _EXCEPTION_POINTERS* */ IntPtr GetExceptionPointers(); + [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern int GetExceptionCode(); diff --git a/src/mscorlib/src/System/Span.cs b/src/mscorlib/src/System/Span.cs deleted file mode 100644 index 4211083def..0000000000 --- a/src/mscorlib/src/System/Span.cs +++ /dev/null @@ -1,910 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Runtime; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; -using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; - -#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' - -#if BIT64 -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - -namespace System -{ - /// - /// Span represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed - /// or native memory, or to memory allocated on the stack. It is type- and memory-safe. - /// - public struct Span - { - /// A byref or a native ptr. - private readonly ByReference _pointer; - /// The number of elements this Span contains. - private readonly int _length; - - /// - /// Creates a new span over the entirety of the target array. - /// - /// The target array. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - /// Thrown when is covariant and array's type is not exactly T[]. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span(T[] array) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (default(T) == null && array.GetType() != typeof(T[])) - ThrowHelper.ThrowArrayTypeMismatchException(); - - _pointer = new ByReference(ref JitHelpers.GetArrayData(array)); - _length = array.Length; - } - - /// - /// Creates a new span over the portion of the target array beginning - /// at 'start' index and covering the remainder of the array. - /// - /// The target array. - /// The index at which to begin the span. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - /// Thrown when is covariant and array's type is not exactly T[]. - /// - /// Thrown when the specified is not in the range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span(T[] array, int start) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (default(T) == null && array.GetType() != typeof(T[])) - ThrowHelper.ThrowArrayTypeMismatchException(); - if ((uint)start > (uint)array.Length) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start)); - _length = array.Length - start; - } - - /// - /// Creates a new span over the portion of the target array beginning - /// at 'start' index and ending at 'end' index (exclusive). - /// - /// The target array. - /// The index at which to begin the span. - /// The number of items in the span. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - /// Thrown when is covariant and array's type is not exactly T[]. - /// - /// Thrown when the specified or end index is not in the range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span(T[] array, int start, int length) - { - if (array == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (default(T) == null && array.GetType() != typeof(T[])) - ThrowHelper.ThrowArrayTypeMismatchException(); - if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start)); - _length = length; - } - - /// - /// Creates a new span over the target unmanaged buffer. Clearly this - /// is quite dangerous, because we are creating arbitrarily typed T's - /// out of a void*-typed block of memory. And the length is not checked. - /// But if this creation is correct, then all subsequent uses are correct. - /// - /// An unmanaged pointer to memory. - /// The number of elements the memory contains. - /// - /// Thrown when is reference type or contains pointers and hence cannot be stored in unmanaged memory. - /// - /// - /// Thrown when the specified is negative. - /// - [CLSCompliant(false)] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe Span(void* pointer, int length) - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); - if (length < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - _pointer = new ByReference(ref Unsafe.As(ref *(byte*)pointer)); - _length = length; - } - - /// - /// Create a new span over a portion of a regular managed object. This can be useful - /// if part of a managed object represents a "fixed array." This is dangerous because neither the - /// is checked, nor being null, nor the fact that - /// "rawPointer" actually lies within . - /// - /// The managed object that contains the data to span over. - /// A reference to data within that object. - /// The number of elements the memory contains. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span DangerousCreate(object obj, ref T objectData, int length) => new Span(ref objectData, length); - - // Constructor for internal use only. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Span(ref T ptr, int length) - { - Debug.Assert(length >= 0); - - _pointer = new ByReference(ref ptr); - _length = length; - } - - /// - /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element - /// would have been stored. Such a reference can be used for pinning but must never be dereferenced. - /// - public ref T DangerousGetPinnableReference() - { - return ref _pointer.Value; - } - - /// - /// The number of items in the span. - /// - public int Length => _length; - - /// - /// Returns true if Length is 0. - /// - public bool IsEmpty => _length == 0; - - /// - /// Returns a reference to specified element of the Span. - /// - /// - /// - /// - /// Thrown when index less than 0 or index greater than or equal to Length - /// - public ref T this[int index] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - if ((uint)index >= (uint)_length) - ThrowHelper.ThrowIndexOutOfRangeException(); - - return ref Unsafe.Add(ref _pointer.Value, index); - } - } - - /// - /// Clears the contents of this span. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - { - SpanHelper.ClearWithReferences(ref Unsafe.As(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf() / sizeof(nuint))); - } - else - { - SpanHelper.ClearWithoutReferences(ref Unsafe.As(ref _pointer.Value), (nuint)_length * (nuint)Unsafe.SizeOf()); - } - } - - /// - /// Fills the contents of this span with the given value. - /// - public void Fill(T value) - { - if (Unsafe.SizeOf() == 1) - { - uint length = (uint)_length; - if (length == 0) - return; - - T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loop below. - Unsafe.InitBlockUnaligned(ref Unsafe.As(ref _pointer.Value), Unsafe.As(ref tmp), length); - } - else - { - // Do all math as nuint to avoid unnecessary 64->32->64 bit integer truncations - nuint length = (uint)_length; - if (length == 0) - return; - - ref T r = ref DangerousGetPinnableReference(); - - // TODO: Create block fill for value types of power of two sizes e.g. 2,4,8,16 - - nuint elementSize = (uint)Unsafe.SizeOf(); - nuint i = 0; - for (; i < (length & ~(nuint)7); i += 8) - { - Unsafe.AddByteOffset(ref r, (i + 0) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 1) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 2) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 3) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 4) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 5) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 6) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 7) * elementSize) = value; - } - if (i < (length & ~(nuint)3)) - { - Unsafe.AddByteOffset(ref r, (i + 0) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 1) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 2) * elementSize) = value; - Unsafe.AddByteOffset(ref r, (i + 3) * elementSize) = value; - i += 4; - } - for (; i < length; i++) - { - Unsafe.AddByteOffset(ref r, i * elementSize) = value; - } - } - } - - /// - /// Copies the contents of this span into destination span. If the source - /// and destinations overlap, this method behaves as if the original values in - /// a temporary location before the destination is overwritten. - /// - /// The span to copy items into. - /// - /// Thrown when the destination Span is shorter than the source Span. - /// - public void CopyTo(Span destination) - { - if (!TryCopyTo(destination)) - ThrowHelper.ThrowArgumentException_DestinationTooShort(); - } - - /// - /// Copies the contents of this span into destination span. If the source - /// and destinations overlap, this method behaves as if the original values in - /// a temporary location before the destination is overwritten. - /// - /// The span to copy items into. - /// If the destination span is shorter than the source span, this method - /// return false and no data is written to the destination. - public bool TryCopyTo(Span destination) - { - if ((uint)_length > (uint)destination.Length) - return false; - - SpanHelper.CopyTo(ref destination._pointer.Value, ref _pointer.Value, _length); - return true; - } - - /// - /// Returns true if left and right point at the same memory and have the same length. Note that - /// this does *not* check to see if the *contents* are equal. - /// - public static bool operator ==(Span left, Span right) - { - return left._length == right._length && Unsafe.AreSame(ref left._pointer.Value, ref right._pointer.Value); - } - - /// - /// Returns false if left and right point at the same memory and have the same length. Note that - /// this does *not* check to see if the *contents* are equal. - /// - public static bool operator !=(Span left, Span right) => !(left == right); - - /// - /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==. - /// - /// Always thrown by this method. - /// - /// - [Obsolete("Equals() on Span will always throw an exception. Use == instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool Equals(object obj) - { - throw new NotSupportedException(SR.NotSupported_CannotCallEqualsOnSpan); - } - - /// - /// This method is not supported as spans cannot be boxed. - /// - /// Always thrown by this method. - /// - /// - [Obsolete("GetHashCode() on Span will always throw an exception.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public override int GetHashCode() - { - throw new NotSupportedException(SR.NotSupported_CannotCallGetHashCodeOnSpan); - } - - /// - /// Defines an implicit conversion of an array to a - /// - public static implicit operator Span(T[] array) => new Span(array); - - /// - /// Defines an implicit conversion of a to a - /// - public static implicit operator Span(ArraySegment arraySegment) => new Span(arraySegment.Array, arraySegment.Offset, arraySegment.Count); - - /// - /// Defines an implicit conversion of a to a - /// - public static implicit operator ReadOnlySpan(Span span) => new ReadOnlySpan(ref span._pointer.Value, span._length); - - /// - /// Forms a slice out of the given span, beginning at 'start'. - /// - /// The index at which to begin this slice. - /// - /// Thrown when the specified index is not in range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span Slice(int start) - { - if ((uint)start > (uint)_length) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new Span(ref Unsafe.Add(ref _pointer.Value, start), _length - start); - } - - /// - /// Forms a slice out of the given span, beginning at 'start', of given length - /// - /// The index at which to begin this slice. - /// The desired length for the slice (exclusive). - /// - /// Thrown when the specified or end index is not in range (<0 or >=Length). - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span Slice(int start, int length) - { - if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start)) - ThrowHelper.ThrowArgumentOutOfRangeException(); - - return new Span(ref Unsafe.Add(ref _pointer.Value, start), length); - } - - /// - /// Copies the contents of this span into a new array. This heap - /// allocates, so should generally be avoided, however it is sometimes - /// necessary to bridge the gap with APIs written in terms of arrays. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T[] ToArray() - { - if (_length == 0) - return Array.Empty(); - - var destination = new T[_length]; - SpanHelper.CopyTo(ref JitHelpers.GetArrayData(destination), ref _pointer.Value, _length); - return destination; - } - - // - /// Returns an empty - /// - public static Span Empty => default(Span); - } - - public static class Span - { - /// - /// Casts a Span of one primitive type to Span of bytes. - /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety. - /// - /// The source slice, of type . - /// - /// Thrown when contains pointers. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span AsBytes(this Span source) - where T : struct - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); - - return new Span( - ref Unsafe.As(ref source.DangerousGetPinnableReference()), - checked(source.Length * Unsafe.SizeOf())); - } - - /// - /// Casts a ReadOnlySpan of one primitive type to ReadOnlySpan of bytes. - /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety. - /// - /// The source slice, of type . - /// - /// Thrown when contains pointers. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsBytes(this ReadOnlySpan source) - where T : struct - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); - - return new ReadOnlySpan( - ref Unsafe.As(ref source.DangerousGetPinnableReference()), - checked(source.Length * Unsafe.SizeOf())); - } - - /// - /// Casts a Span of one primitive type to another primitive type . - /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety. - /// - /// - /// Supported only for platforms that support misaligned memory access. - /// - /// The source slice, of type . - /// - /// Thrown when or contains pointers. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span NonPortableCast(this Span source) - where TFrom : struct - where TTo : struct - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); - - return new Span( - ref Unsafe.As(ref source.DangerousGetPinnableReference()), - checked((int)((long)source.Length * Unsafe.SizeOf() / Unsafe.SizeOf()))); - } - - /// - /// Casts a ReadOnlySpan of one primitive type to another primitive type . - /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety. - /// - /// - /// Supported only for platforms that support misaligned memory access. - /// - /// The source slice, of type . - /// - /// Thrown when or contains pointers. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan NonPortableCast(this ReadOnlySpan source) - where TFrom : struct - where TTo : struct - { - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom)); - if (RuntimeHelpers.IsReferenceOrContainsReferences()) - ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo)); - - return new ReadOnlySpan( - ref Unsafe.As(ref source.DangerousGetPinnableReference()), - checked((int)((long)source.Length * Unsafe.SizeOf() / Unsafe.SizeOf()))); - } - - /// - /// Creates a new readonly span over the portion of the target string. - /// - /// The target string. - /// Thrown when is a null - /// reference (Nothing in Visual Basic). - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsSpan(this string text) - { - if (text == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text); - - return new ReadOnlySpan(ref text.GetFirstCharRef(), text.Length); - } - } - - internal static class SpanHelper - { - internal static unsafe void CopyTo(ref T destination, ref T source, int elementsCount) - { - if (Unsafe.AreSame(ref destination, ref source)) - return; - - if (elementsCount <= 1) - { - if (elementsCount == 1) - { - destination = source; - } - return; - } - - nuint byteCount = (nuint)elementsCount * (nuint)Unsafe.SizeOf(); - if (!RuntimeHelpers.IsReferenceOrContainsReferences()) - { - fixed (byte* pDestination = &Unsafe.As(ref destination)) - { - fixed (byte* pSource = &Unsafe.As(ref source)) - { - Buffer.Memmove(pDestination, pSource, byteCount); - } - } - } - else - { - RuntimeImports.RhBulkMoveWithWriteBarrier( - ref Unsafe.As(ref destination), - ref Unsafe.As(ref source), - byteCount); - } - } - - internal static unsafe void ClearWithoutReferences(ref byte b, nuint byteLength) - { - if (byteLength == 0) - return; - -#if AMD64 - if (byteLength > 4096) goto PInvoke; - Unsafe.InitBlockUnaligned(ref b, 0, (uint)byteLength); - return; -#else // AMD64 - // TODO: Optimize this method on X86 machine - // Note: It's important that this switch handles lengths at least up to 22. - // See notes below near the main loop for why. - - // The switch will be very fast since it can be implemented using a jump - // table in assembly. See http://stackoverflow.com/a/449297/4077294 for more info. - - switch (byteLength) - { - case 1: - b = 0; - return; - case 2: - Unsafe.As(ref b) = 0; - return; - case 3: - Unsafe.As(ref b) = 0; - Unsafe.Add(ref b, 2) = 0; - return; - case 4: - Unsafe.As(ref b) = 0; - return; - case 5: - Unsafe.As(ref b) = 0; - Unsafe.Add(ref b, 4) = 0; - return; - case 6: - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; - return; - case 7: - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; - Unsafe.Add(ref b, 6) = 0; - return; - case 8: -#if BIT64 - Unsafe.As(ref b) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; -#endif - return; - case 9: -#if BIT64 - Unsafe.As(ref b) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; -#endif - Unsafe.Add(ref b, 8) = 0; - return; - case 10: -#if BIT64 - Unsafe.As(ref b) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - return; - case 11: -#if BIT64 - Unsafe.As(ref b) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.Add(ref b, 10) = 0; - return; - case 12: -#if BIT64 - Unsafe.As(ref b) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - return; - case 13: -#if BIT64 - Unsafe.As(ref b) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.Add(ref b, 12) = 0; - return; - case 14: -#if BIT64 - Unsafe.As(ref b) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 12)) = 0; - return; - case 15: -#if BIT64 - Unsafe.As(ref b) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 12)) = 0; - Unsafe.Add(ref b, 14) = 0; - return; - case 16: -#if BIT64 - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 12)) = 0; -#endif - return; - case 17: -#if BIT64 - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 12)) = 0; -#endif - Unsafe.Add(ref b, 16) = 0; - return; - case 18: -#if BIT64 - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 12)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 16)) = 0; - return; - case 19: -#if BIT64 - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 12)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 16)) = 0; - Unsafe.Add(ref b, 18) = 0; - return; - case 20: -#if BIT64 - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 12)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 16)) = 0; - return; - case 21: -#if BIT64 - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 12)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 16)) = 0; - Unsafe.Add(ref b, 20) = 0; - return; - case 22: -#if BIT64 - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; -#else - Unsafe.As(ref b) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 4)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 8)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 12)) = 0; -#endif - Unsafe.As(ref Unsafe.Add(ref b, 16)) = 0; - Unsafe.As(ref Unsafe.Add(ref b, 20)) = 0; - return; - } - - // P/Invoke into the native version for large lengths - if (byteLength >= 512) goto PInvoke; - - nuint i = 0; // byte offset at which we're copying - - if ((Unsafe.As(ref b) & 3) != 0) - { - if ((Unsafe.As(ref b) & 1) != 0) - { - Unsafe.AddByteOffset(ref b, i) = 0; - i += 1; - if ((Unsafe.As(ref b) & 2) != 0) - goto IntAligned; - } - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i)) = 0; - i += 2; - } - - IntAligned: - - // On 64-bit IntPtr.Size == 8, so we want to advance to the next 8-aligned address. If - // (int)b % 8 is 0, 5, 6, or 7, we will already have advanced by 0, 3, 2, or 1 - // bytes to the next aligned address (respectively), so do nothing. On the other hand, - // if it is 1, 2, 3, or 4 we will want to copy-and-advance another 4 bytes until - // we're aligned. - // The thing 1, 2, 3, and 4 have in common that the others don't is that if you - // subtract one from them, their 3rd lsb will not be set. Hence, the below check. - - if (((Unsafe.As(ref b) - 1) & 4) == 0) - { - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i)) = 0; - i += 4; - } - - nuint end = byteLength - 16; - byteLength -= i; // lower 4 bits of byteLength represent how many bytes are left *after* the unrolled loop - - // We know due to the above switch-case that this loop will always run 1 iteration; max - // bytes we clear before checking is 23 (7 to align the pointers, 16 for 1 iteration) so - // the switch handles lengths 0-22. - Debug.Assert(end >= 7 && i <= end); - - // This is separated out into a different variable, so the i + 16 addition can be - // performed at the start of the pipeline and the loop condition does not have - // a dependency on the writes. - nuint counter; - - do - { - counter = i + 16; - - // This loop looks very costly since there appear to be a bunch of temporary values - // being created with the adds, but the jit (for x86 anyways) will convert each of - // these to use memory addressing operands. - - // So the only cost is a bit of code size, which is made up for by the fact that - // we save on writes to b. - -#if BIT64 - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i)) = 0; - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i + 8)) = 0; -#else - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i)) = 0; - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i + 4)) = 0; - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i + 8)) = 0; - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i + 12)) = 0; -#endif - - i = counter; - - // See notes above for why this wasn't used instead - // i += 16; - } - while (counter <= end); - - if ((byteLength & 8) != 0) - { -#if BIT64 - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i)) = 0; -#else - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i)) = 0; - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i + 4)) = 0; -#endif - i += 8; - } - if ((byteLength & 4) != 0) - { - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i)) = 0; - i += 4; - } - if ((byteLength & 2) != 0) - { - Unsafe.As(ref Unsafe.AddByteOffset(ref b, i)) = 0; - i += 2; - } - if ((byteLength & 1) != 0) - { - Unsafe.AddByteOffset(ref b, i) = 0; - // We're not using i after this, so not needed - // i += 1; - } - - return; -#endif // AMD64 - - PInvoke: - RuntimeImports.RhZeroMemory(ref b, byteLength); - } - - internal static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLength) - { - if (pointerSizeLength == 0) - return; - - // TODO: Perhaps do switch casing to improve small size perf - - nuint i = 0; - nuint n = 0; - while ((n = i + 8) <= (pointerSizeLength)) - { - Unsafe.AddByteOffset(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 4) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 5) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 6) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 7) * (nuint)sizeof(IntPtr)) = default(IntPtr); - i = n; - } - if ((n = i + 4) <= (pointerSizeLength)) - { - Unsafe.AddByteOffset(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr); - i = n; - } - if ((n = i + 2) <= (pointerSizeLength)) - { - Unsafe.AddByteOffset(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr); - Unsafe.AddByteOffset(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr); - i = n; - } - if ((i + 1) <= (pointerSizeLength)) - { - Unsafe.AddByteOffset(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr); - } - } - } -} diff --git a/src/mscorlib/src/System/String.Manipulation.cs b/src/mscorlib/src/System/String.Manipulation.cs index 33e341c58e..b71ffa2f63 100644 --- a/src/mscorlib/src/System/String.Manipulation.cs +++ b/src/mscorlib/src/System/String.Manipulation.cs @@ -1022,8 +1022,10 @@ namespace System { if (oldValue == null) throw new ArgumentNullException(nameof(oldValue)); + if (oldValue.Length == 0) + throw new ArgumentException(SR.Argument_StringZeroLength, nameof(oldValue)); - // If they asked to replace oldValue with a null, replace all occurences + // If they asked to replace oldValue with a null, replace all occurrences // with the empty string. if (newValue == null) newValue = string.Empty; @@ -1037,10 +1039,11 @@ namespace System int matchLength = 0; bool hasDoneAnyReplacements = false; + CompareInfo ci = referenceCulture.CompareInfo; do { - index = referenceCulture.CompareInfo.IndexOfCore(this, oldValue, startIndex, m_stringLength - startIndex, options, &matchLength); + index = ci.IndexOf(this, oldValue, startIndex, m_stringLength - startIndex, options, &matchLength); if (index >= 0) { // append the unmodified portion of string diff --git a/src/mscorlib/src/System/String.cs b/src/mscorlib/src/System/String.cs index f3a4d0f197..0a17c1ee24 100644 --- a/src/mscorlib/src/System/String.cs +++ b/src/mscorlib/src/System/String.cs @@ -876,7 +876,7 @@ namespace System } } - internal ref char GetFirstCharRef() + internal ref char GetRawStringData() { return ref m_firstChar; } diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs index 8e2e6a4cb0..0a9248cba8 100644 --- a/src/mscorlib/src/System/Threading/Tasks/Task.cs +++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs @@ -1467,8 +1467,7 @@ namespace System.Threading.Tasks return (flags & TASK_STATE_COMPLETED_MASK) != 0; } - // For use in InternalWait -- marginally faster than (Task.Status == TaskStatus.RanToCompletion) - internal bool IsRanToCompletion + public bool IsCompletedSuccessfully { get { return (m_stateFlags & TASK_STATE_COMPLETED_MASK) == TASK_STATE_RAN_TO_COMPLETION; } } diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs index 848a0ecbc2..de222352c9 100644 --- a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs +++ b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs @@ -320,7 +320,7 @@ namespace System.Threading.Tasks // activation criteria of the TaskContinuationOptions. TaskContinuationOptions options = m_options; bool isRightKind = - completedTask.IsRanToCompletion ? + completedTask.IsCompletedSuccessfully ? (options & TaskContinuationOptions.NotOnRanToCompletion) == 0 : (completedTask.IsCanceled ? (options & TaskContinuationOptions.NotOnCanceled) == 0 : diff --git a/src/mscorlib/src/System/Threading/Tasks/future.cs b/src/mscorlib/src/System/Threading/Tasks/future.cs index 26c2388e6b..bf9000ea00 100644 --- a/src/mscorlib/src/System/Threading/Tasks/future.cs +++ b/src/mscorlib/src/System/Threading/Tasks/future.cs @@ -374,7 +374,7 @@ namespace System.Threading.Tasks { get { - return IsRanToCompletion ? "" + m_result : SR.TaskT_DebuggerNoResult; + return IsCompletedSuccessfully ? "" + m_result : SR.TaskT_DebuggerNoResult; } } @@ -491,10 +491,10 @@ namespace System.Threading.Tasks if (waitCompletionNotification) NotifyDebuggerOfWaitCompletionIfNecessary(); // Throw an exception if appropriate. - if (!IsRanToCompletion) ThrowIfExceptional(includeTaskCanceledExceptions: true); + if (!IsCompletedSuccessfully) ThrowIfExceptional(includeTaskCanceledExceptions: true); // We shouldn't be here if the result has not been set. - Debug.Assert(IsRanToCompletion, "Task.Result getter: Expected result to have been set."); + Debug.Assert(IsCompletedSuccessfully, "Task.Result getter: Expected result to have been set."); return m_result; } diff --git a/src/mscorlib/src/System/ThrowHelper.cs b/src/mscorlib/src/System/ThrowHelper.cs index 4dcf8d4511..ff76738e8e 100644 --- a/src/mscorlib/src/System/ThrowHelper.cs +++ b/src/mscorlib/src/System/ThrowHelper.cs @@ -416,6 +416,7 @@ namespace System type, stateMachine, pHandle, + values } // diff --git a/src/mscorlib/src/System/TimeZoneInfo.Win32.cs b/src/mscorlib/src/System/TimeZoneInfo.Win32.cs index b6585bd0a0..4f740bd355 100644 --- a/src/mscorlib/src/System/TimeZoneInfo.Win32.cs +++ b/src/mscorlib/src/System/TimeZoneInfo.Win32.cs @@ -398,7 +398,7 @@ namespace System baseOffset = baseOffset + match.Rule.BaseUtcOffsetDelta; if (match.Rule.HasDaylightSaving) { - isDaylightSavings = GetIsDaylightSavingsFromUtc(time, timeYear, match.Offset, match.Rule, out isAmbiguousLocalDst, Local); + isDaylightSavings = GetIsDaylightSavingsFromUtc(time, timeYear, match.Offset, match.Rule, null, out isAmbiguousLocalDst, Local); baseOffset += (isDaylightSavings ? match.Rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); } } @@ -576,8 +576,8 @@ namespace System // read LastEntry {(yearN, 1, 1) - MaxValue } // read the FirstEntry and LastEntry key values (ex: "1980", "2038") - int first = (int)dynamicKey.GetValue(FirstEntryValue, -1); - int last = (int)dynamicKey.GetValue(LastEntryValue, -1); + int first = (int)dynamicKey.GetValue(FirstEntryValue, -1, RegistryValueOptions.None); + int last = (int)dynamicKey.GetValue(LastEntryValue, -1, RegistryValueOptions.None); if (first == -1 || last == -1 || first > last) { @@ -587,7 +587,7 @@ namespace System // read the first year entry Win32Native.RegistryTimeZoneInformation dtzi; - byte[] regValue = dynamicKey.GetValue(first.ToString(CultureInfo.InvariantCulture)) as byte[]; + byte[] regValue = dynamicKey.GetValue(first.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[]; if (regValue == null || regValue.Length != RegByteLength) { rules = null; @@ -620,7 +620,7 @@ namespace System // read the middle year entries for (int i = first + 1; i < last; i++) { - regValue = dynamicKey.GetValue(i.ToString(CultureInfo.InvariantCulture)) as byte[]; + regValue = dynamicKey.GetValue(i.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[]; if (regValue == null || regValue.Length != RegByteLength) { rules = null; @@ -640,7 +640,7 @@ namespace System } // read the last year entry - regValue = dynamicKey.GetValue(last.ToString(CultureInfo.InvariantCulture)) as byte[]; + regValue = dynamicKey.GetValue(last.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[]; dtzi = new Win32Native.RegistryTimeZoneInformation(regValue); if (regValue == null || regValue.Length != RegByteLength) { @@ -719,7 +719,7 @@ namespace System } Win32Native.RegistryTimeZoneInformation registryTimeZoneInfo; - byte[] regValue = key.GetValue(TimeZoneInfoValue) as byte[]; + byte[] regValue = key.GetValue(TimeZoneInfoValue, null, RegistryValueOptions.None) as byte[]; if (regValue == null || regValue.Length != RegByteLength) return false; registryTimeZoneInfo = new Win32Native.RegistryTimeZoneInformation(regValue); @@ -756,7 +756,7 @@ namespace System // if (result) { - string registryStandardName = key.GetValue(StandardValue, string.Empty) as string; + string registryStandardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string; result = string.Equals(registryStandardName, timeZone.StandardName, StringComparison.Ordinal); } return result; @@ -884,9 +884,9 @@ namespace System daylightName = string.Empty; // read the MUI_ registry keys - string displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty) as string; - string standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty) as string; - string daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty) as string; + string displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty, RegistryValueOptions.None) as string; + string standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty, RegistryValueOptions.None) as string; + string daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty, RegistryValueOptions.None) as string; // try to load the strings from the native resource DLL(s) if (!string.IsNullOrEmpty(displayNameMuiResource)) @@ -907,15 +907,15 @@ namespace System // fallback to using the standard registry keys if (string.IsNullOrEmpty(displayName)) { - displayName = key.GetValue(DisplayValue, string.Empty) as string; + displayName = key.GetValue(DisplayValue, string.Empty, RegistryValueOptions.None) as string; } if (string.IsNullOrEmpty(standardName)) { - standardName = key.GetValue(StandardValue, string.Empty) as string; + standardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string; } if (string.IsNullOrEmpty(daylightName)) { - daylightName = key.GetValue(DaylightValue, string.Empty) as string; + daylightName = key.GetValue(DaylightValue, string.Empty, RegistryValueOptions.None) as string; } return true; @@ -964,7 +964,7 @@ namespace System } Win32Native.RegistryTimeZoneInformation defaultTimeZoneInformation; - byte[] regValue = key.GetValue(TimeZoneInfoValue) as byte[]; + byte[] regValue = key.GetValue(TimeZoneInfoValue, null, RegistryValueOptions.None) as byte[]; if (regValue == null || regValue.Length != RegByteLength) { // the registry value could not be cast to a byte array diff --git a/src/mscorlib/src/System/TimeZoneInfo.cs b/src/mscorlib/src/System/TimeZoneInfo.cs index 29ea33a8ad..8ed7e229c0 100644 --- a/src/mscorlib/src/System/TimeZoneInfo.cs +++ b/src/mscorlib/src/System/TimeZoneInfo.cs @@ -172,10 +172,11 @@ namespace System DateTime adjustedTime = ConvertTime(dateTimeOffset, this).DateTime; bool isAmbiguous = false; - AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime); + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); if (rule != null && rule.HasDaylightSaving) { - DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); } @@ -232,10 +233,11 @@ namespace System } bool isAmbiguous = false; - AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime); + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); if (rule != null && rule.HasDaylightSaving) { - DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); isAmbiguous = GetIsAmbiguousTime(adjustedTime, rule, daylightTime); } @@ -263,15 +265,15 @@ namespace System } // note the time is already adjusted - private AdjustmentRule GetAdjustmentRuleForAmbiguousOffsets(DateTime adjustedTime) + private AdjustmentRule GetAdjustmentRuleForAmbiguousOffsets(DateTime adjustedTime, out int? ruleIndex) { - AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime); + AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); if (rule != null && rule.NoDaylightTransitions && !rule.HasDaylightSaving) { // When using NoDaylightTransitions rules, each rule is only for one offset. // When looking for the Daylight savings rules, and we found the non-DST rule, // then we get the rule right before this rule. - return GetPreviousAdjustmentRule(rule); + return GetPreviousAdjustmentRule(rule, ruleIndex); } return rule; @@ -282,12 +284,23 @@ namespace System /// If the specified rule is the first AdjustmentRule, or it isn't in _adjustmentRules, /// then the specified rule is returned. /// - private AdjustmentRule GetPreviousAdjustmentRule(AdjustmentRule rule) + private AdjustmentRule GetPreviousAdjustmentRule(AdjustmentRule rule, int? ruleIndex) { + Debug.Assert(rule.NoDaylightTransitions, "GetPreviousAdjustmentRule should only be used with NoDaylightTransitions rules."); + + if (ruleIndex.HasValue && 0 < ruleIndex.Value && ruleIndex.Value < _adjustmentRules.Length) + { + return _adjustmentRules[ruleIndex.Value - 1]; + } + AdjustmentRule result = rule; for (int i = 1; i < _adjustmentRules.Length; i++) { - if (rule.Equals(_adjustmentRules[i])) + // use ReferenceEquals here instead of AdjustmentRule.Equals because + // ReferenceEquals is much faster. This is safe because all the callers + // of GetPreviousAdjustmentRule pass in a rule that was retrieved from + // _adjustmentRules. A different approach will be needed if this ever changes. + if (ReferenceEquals(rule, _adjustmentRules[i])) { result = _adjustmentRules[i - 1]; break; @@ -407,10 +420,11 @@ namespace System dateTime.Kind == DateTimeKind.Utc ? ConvertTime(dateTime, s_utcTimeZone, this, flags, cachedData) : dateTime; - AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime); + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); if (rule != null && rule.HasDaylightSaving) { - DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); return GetIsAmbiguousTime(adjustedTime, rule, daylightTime); } return false; @@ -492,10 +506,11 @@ namespace System // // handle the normal cases... // - AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime); + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); if (rule != null && rule.HasDaylightSaving) { - DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); return GetIsDaylightSavings(adjustedTime, rule, daylightTime, flags); } else @@ -515,11 +530,12 @@ namespace System (dateTime.Kind == DateTimeKind.Local && s_cachedData.GetCorrespondingKind(this) == DateTimeKind.Local)) { // only check Unspecified and (Local when this TimeZoneInfo instance is Local) - AdjustmentRule rule = GetAdjustmentRuleForTime(dateTime); + int? ruleIndex; + AdjustmentRule rule = GetAdjustmentRuleForTime(dateTime, out ruleIndex); if (rule != null && rule.HasDaylightSaving) { - DaylightTimeStruct daylightTime = GetDaylightTime(dateTime.Year, rule); + DaylightTimeStruct daylightTime = GetDaylightTime(dateTime.Year, rule, ruleIndex); isInvalid = GetIsInvalidTime(dateTime, rule, daylightTime); } else @@ -661,7 +677,8 @@ namespace System // performance for the normal case at the expense of the 'ArgumentException' // case and Loss-less Local special cases. // - AdjustmentRule sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime); + int? sourceRuleIndex; + AdjustmentRule sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime, out sourceRuleIndex); TimeSpan sourceOffset = sourceTimeZone.BaseUtcOffset; if (sourceRule != null) @@ -670,7 +687,7 @@ namespace System if (sourceRule.HasDaylightSaving) { bool sourceIsDaylightSavings = false; - DaylightTimeStruct sourceDaylightTime = sourceTimeZone.GetDaylightTime(dateTime.Year, sourceRule); + DaylightTimeStruct sourceDaylightTime = sourceTimeZone.GetDaylightTime(dateTime.Year, sourceRule, sourceRuleIndex); // 'dateTime' might be in an invalid time range since it is in an AdjustmentRule // period that supports DST @@ -1048,10 +1065,19 @@ namespace System _supportsDaylightSavingTime = (bool)info.GetValue("SupportsDaylightSavingTime", typeof(bool)); } - private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, bool dateTimeisUtc = false) + private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, out int? ruleIndex) + { + AdjustmentRule result = GetAdjustmentRuleForTime(dateTime, dateTimeisUtc: false, ruleIndex: out ruleIndex); + Debug.Assert(result == null || ruleIndex.HasValue, "If an AdjustmentRule was found, ruleIndex should also be set."); + + return result; + } + + private AdjustmentRule GetAdjustmentRuleForTime(DateTime dateTime, bool dateTimeisUtc, out int? ruleIndex) { if (_adjustmentRules == null || _adjustmentRules.Length == 0) { + ruleIndex = null; return null; } @@ -1076,6 +1102,7 @@ namespace System int compareResult = CompareAdjustmentRuleToDateTime(rule, previousRule, dateTime, date, dateTimeisUtc); if (compareResult == 0) { + ruleIndex = median; return rule; } else if (compareResult < 0) @@ -1088,6 +1115,7 @@ namespace System } } + ruleIndex = null; return null; } @@ -1199,7 +1227,7 @@ namespace System /// /// Helper function that returns a DaylightTime from a year and AdjustmentRule. /// - private DaylightTimeStruct GetDaylightTime(int year, AdjustmentRule rule) + private DaylightTimeStruct GetDaylightTime(int year, AdjustmentRule rule, int? ruleIndex) { TimeSpan delta = rule.DaylightDelta; DateTime startTime; @@ -1211,7 +1239,7 @@ namespace System // Convert the UTC times into adjusted time zone times. // use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule - AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule); + AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex); startTime = ConvertFromUtc(rule.DateStart, previousRule.DaylightDelta, previousRule.BaseUtcOffsetDelta); endTime = ConvertFromUtc(rule.DateEnd, rule.DaylightDelta, rule.BaseUtcOffsetDelta); @@ -1301,12 +1329,12 @@ namespace System /// /// Gets the offset that should be used to calculate DST start times from a UTC time. /// - private TimeSpan GetDaylightSavingsStartOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule) + private TimeSpan GetDaylightSavingsStartOffsetFromUtc(TimeSpan baseUtcOffset, AdjustmentRule rule, int? ruleIndex) { if (rule.NoDaylightTransitions) { // use the previous rule to calculate the startTime, since the DST change happens w.r.t. the previous rule - AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule); + AdjustmentRule previousRule = GetPreviousAdjustmentRule(rule, ruleIndex); return baseUtcOffset + previousRule.BaseUtcOffsetDelta + previousRule.DaylightDelta; } else @@ -1328,7 +1356,7 @@ namespace System /// Helper function that checks if a given dateTime is in Daylight Saving Time (DST). /// This function assumes the dateTime is in UTC and AdjustmentRule is in a different time zone. /// - private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpan utc, AdjustmentRule rule, out bool isAmbiguousLocalDst, TimeZoneInfo zone) + private static bool GetIsDaylightSavingsFromUtc(DateTime time, int year, TimeSpan utc, AdjustmentRule rule, int? ruleIndex, out bool isAmbiguousLocalDst, TimeZoneInfo zone) { isAmbiguousLocalDst = false; @@ -1338,7 +1366,7 @@ namespace System } // Get the daylight changes for the year of the specified time. - DaylightTimeStruct daylightTime = zone.GetDaylightTime(year, rule); + DaylightTimeStruct daylightTime = zone.GetDaylightTime(year, rule, ruleIndex); // The start and end times represent the range of universal times that are in DST for that year. // Within that there is an ambiguous hour, usually right at the end, but at the beginning in @@ -1352,14 +1380,20 @@ namespace System // Note we handle the similar case when rule year start with daylight saving and previous year end with daylight saving. bool ignoreYearAdjustment = false; - TimeSpan dstStartOffset = zone.GetDaylightSavingsStartOffsetFromUtc(utc, rule); + TimeSpan dstStartOffset = zone.GetDaylightSavingsStartOffsetFromUtc(utc, rule, ruleIndex); DateTime startTime; if (rule.IsStartDateMarkerForBeginningOfYear() && daylightTime.Start.Year > DateTime.MinValue.Year) { - AdjustmentRule previousYearRule = zone.GetAdjustmentRuleForTime(new DateTime(daylightTime.Start.Year - 1, 12, 31)); + int? previousYearRuleIndex; + AdjustmentRule previousYearRule = zone.GetAdjustmentRuleForTime( + new DateTime(daylightTime.Start.Year - 1, 12, 31), + out previousYearRuleIndex); if (previousYearRule != null && previousYearRule.IsEndDateMarkerForEndOfYear()) { - DaylightTimeStruct previousDaylightTime = zone.GetDaylightTime(daylightTime.Start.Year - 1, previousYearRule); + DaylightTimeStruct previousDaylightTime = zone.GetDaylightTime( + daylightTime.Start.Year - 1, + previousYearRule, + previousYearRuleIndex); startTime = previousDaylightTime.Start - utc - previousYearRule.BaseUtcOffsetDelta; ignoreYearAdjustment = true; } @@ -1377,7 +1411,10 @@ namespace System DateTime endTime; if (rule.IsEndDateMarkerForEndOfYear() && daylightTime.End.Year < DateTime.MaxValue.Year) { - AdjustmentRule nextYearRule = zone.GetAdjustmentRuleForTime(new DateTime(daylightTime.End.Year + 1, 1, 1)); + int? nextYearRuleIndex; + AdjustmentRule nextYearRule = zone.GetAdjustmentRuleForTime( + new DateTime(daylightTime.End.Year + 1, 1, 1), + out nextYearRuleIndex); if (nextYearRule != null && nextYearRule.IsStartDateMarkerForBeginningOfYear()) { if (nextYearRule.IsEndDateMarkerForEndOfYear()) @@ -1387,7 +1424,10 @@ namespace System } else { - DaylightTimeStruct nextdaylightTime = zone.GetDaylightTime(daylightTime.End.Year + 1, nextYearRule); + DaylightTimeStruct nextdaylightTime = zone.GetDaylightTime( + daylightTime.End.Year + 1, + nextYearRule, + nextYearRuleIndex); endTime = nextdaylightTime.End - utc - nextYearRule.BaseUtcOffsetDelta - nextYearRule.DaylightDelta; } ignoreYearAdjustment = true; @@ -1644,14 +1684,15 @@ namespace System private static TimeSpan GetUtcOffset(DateTime time, TimeZoneInfo zone, TimeZoneInfoOptions flags) { TimeSpan baseOffset = zone.BaseUtcOffset; - AdjustmentRule rule = zone.GetAdjustmentRuleForTime(time); + int? ruleIndex; + AdjustmentRule rule = zone.GetAdjustmentRuleForTime(time, out ruleIndex); if (rule != null) { baseOffset = baseOffset + rule.BaseUtcOffsetDelta; if (rule.HasDaylightSaving) { - DaylightTimeStruct daylightTime = zone.GetDaylightTime(time.Year, rule); + DaylightTimeStruct daylightTime = zone.GetDaylightTime(time.Year, rule, ruleIndex); bool isDaylightSavings = GetIsDaylightSavings(time, rule, daylightTime, flags); baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); } @@ -1690,21 +1731,24 @@ namespace System isAmbiguousLocalDst = false; TimeSpan baseOffset = zone.BaseUtcOffset; int year; + int? ruleIndex; AdjustmentRule rule; if (time > s_maxDateOnly) { - rule = zone.GetAdjustmentRuleForTime(DateTime.MaxValue); + rule = zone.GetAdjustmentRuleForTime(DateTime.MaxValue, out ruleIndex); year = 9999; } else if (time < s_minDateOnly) { - rule = zone.GetAdjustmentRuleForTime(DateTime.MinValue); + rule = zone.GetAdjustmentRuleForTime(DateTime.MinValue, out ruleIndex); year = 1; } else { - rule = zone.GetAdjustmentRuleForTime(time, dateTimeisUtc: true); + rule = zone.GetAdjustmentRuleForTime(time, dateTimeisUtc: true, ruleIndex: out ruleIndex); + Debug.Assert(rule == null || ruleIndex.HasValue, + "If GetAdjustmentRuleForTime returned an AdjustmentRule, ruleIndex should also be set."); // As we get the associated rule using the adjusted targetTime, we should use the adjusted year (targetTime.Year) too as after adding the baseOffset, // sometimes the year value can change if the input datetime was very close to the beginning or the end of the year. Examples of such cases: @@ -1719,7 +1763,7 @@ namespace System baseOffset = baseOffset + rule.BaseUtcOffsetDelta; if (rule.HasDaylightSaving) { - isDaylightSavings = GetIsDaylightSavingsFromUtc(time, year, zone._baseUtcOffset, rule, out isAmbiguousLocalDst, zone); + isDaylightSavings = GetIsDaylightSavingsFromUtc(time, year, zone._baseUtcOffset, rule, ruleIndex, out isAmbiguousLocalDst, zone); baseOffset += (isDaylightSavings ? rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */); } } -- cgit v1.2.3