diff options
author | Jiyoung Yun <jy910.yun@samsung.com> | 2017-02-10 20:35:12 +0900 |
---|---|---|
committer | Jiyoung Yun <jy910.yun@samsung.com> | 2017-02-10 20:35:12 +0900 |
commit | 4b11dc566a5bbfa1378d6266525c281b028abcc8 (patch) | |
tree | b48831a898906734f8884d08b6e18f1144ee2b82 /src/mscorlib/src/System/Runtime/CompilerServices | |
parent | db20f3f1bb8595633a7e16c8900fd401a453a6b5 (diff) | |
download | coreclr-4b11dc566a5bbfa1378d6266525c281b028abcc8.tar.gz coreclr-4b11dc566a5bbfa1378d6266525c281b028abcc8.tar.bz2 coreclr-4b11dc566a5bbfa1378d6266525c281b028abcc8.zip |
Imported Upstream version 1.0.0.9910upstream/1.0.0.9910
Diffstat (limited to 'src/mscorlib/src/System/Runtime/CompilerServices')
23 files changed, 408 insertions, 216 deletions
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/AccessedThroughPropertyAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/AccessedThroughPropertyAttribute.cs index b0010fd7bd..34e66beade 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/AccessedThroughPropertyAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/AccessedThroughPropertyAttribute.cs @@ -9,7 +9,6 @@ namespace System.Runtime.CompilerServices using System; [AttributeUsage(AttributeTargets.Field)] -[System.Runtime.InteropServices.ComVisible(true)] public sealed class AccessedThroughPropertyAttribute : Attribute { private readonly string propertyName; diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/AssemblyAttributesGoHere.cs b/src/mscorlib/src/System/Runtime/CompilerServices/AssemblyAttributesGoHere.cs deleted file mode 100644 index c021353475..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/AssemblyAttributesGoHere.cs +++ /dev/null @@ -1,43 +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. - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -namespace System.Runtime.CompilerServices { - - using System; - - // NOTE TO DEVELOPERS: These classes are used by ALink (the assembly linker). - // They're used for metadata tokens for making multi-module assemblies. - // Do not randomly touch these classes. - [System.Runtime.CompilerServices.FriendAccessAllowed] - internal sealed class AssemblyAttributesGoHere - { - - internal AssemblyAttributesGoHere() - { - } - } - [System.Runtime.CompilerServices.FriendAccessAllowed] - internal sealed class AssemblyAttributesGoHereS - { - internal AssemblyAttributesGoHereS() - { - } - } - [System.Runtime.CompilerServices.FriendAccessAllowed] - internal sealed class AssemblyAttributesGoHereM - { - internal AssemblyAttributesGoHereM() - { - } - } - [System.Runtime.CompilerServices.FriendAccessAllowed] - internal sealed class AssemblyAttributesGoHereSM - { - internal AssemblyAttributesGoHereSM() - { - } - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs index 6a16462383..afb0c22778 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs @@ -18,7 +18,6 @@ using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Runtime.ExceptionServices; using System.Security; -using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; @@ -840,36 +839,6 @@ namespace System.Runtime.CompilerServices // This method is copy&pasted into the public Start methods to avoid size overhead of valuetype generic instantiations. // Ideally, we would build intrinsics to get the raw ref address and raw code address of MoveNext, and just use the shared implementation. -#if false - /// <summary>Initiates the builder's execution with the associated state machine.</summary> - /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam> - /// <param name="stateMachine">The state machine instance, passed by reference.</param> - /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument is null (Nothing in Visual Basic).</exception> - [DebuggerStepThrough] - internal static void Start<TStateMachine>(ref TStateMachine stateMachine) - where TStateMachine : IAsyncStateMachine - { - if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine)); - Contract.EndContractBlock(); - - // Run the MoveNext method within a copy-on-write ExecutionContext scope. - // This allows us to undo any ExecutionContext changes made in MoveNext, - // so that they won't "leak" out of the first await. - - Thread currentThread = Thread.CurrentThread; - ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - ExecutionContext.EstablishCopyOnWriteScope(currentThread, ref ecs); - stateMachine.MoveNext(); - } - finally - { - ecs.Undo(currentThread); - } - } -#endif /// <summary>Associates the builder with the state machine it represents.</summary> /// <param name="stateMachine">The heap-allocated state machine object.</param> @@ -906,12 +875,12 @@ namespace System.Runtime.CompilerServices Debugger.NotifyOfCrossThreadDependency(); // The builder needs to flow ExecutionContext, so capture it. - var capturedContext = ExecutionContext.FastCapture(); // ok to use FastCapture as we haven't made any permission demands/asserts + var capturedContext = ExecutionContext.Capture(); // If the ExecutionContext is the default context, try to use a cached delegate, creating one if necessary. Action action; MoveNextRunner runner; - if (capturedContext != null && capturedContext.IsPreAllocatedDefault) + if (capturedContext == ExecutionContext.Default) { // Get the cached delegate, and if it's non-null, return it. action = m_defaultContextAction; @@ -1046,12 +1015,8 @@ namespace System.Runtime.CompilerServices if (m_context != null) { - try - { - // Use the context and callback to invoke m_stateMachine.MoveNext. - ExecutionContext.Run(m_context, InvokeMoveNextCallback, m_stateMachine, preserveSyncCtx: true); - } - finally { m_context.Dispose(); } + // Use the context and callback to invoke m_stateMachine.MoveNext. + ExecutionContext.Run(m_context, InvokeMoveNextCallback, m_stateMachine); } else { @@ -1076,24 +1041,11 @@ namespace System.Runtime.CompilerServices internal void RunWithDefaultContext() { Debug.Assert(m_stateMachine != null, "The state machine must have been set before calling Run."); - ExecutionContext.Run(ExecutionContext.PreAllocatedDefault, InvokeMoveNextCallback, m_stateMachine, preserveSyncCtx: true); + ExecutionContext.Run(ExecutionContext.Default, InvokeMoveNextCallback, m_stateMachine); } /// <summary>Gets a delegate to the InvokeMoveNext method.</summary> - protected static ContextCallback InvokeMoveNextCallback - { - get { return s_invokeMoveNext ?? (s_invokeMoveNext = InvokeMoveNext); } - } - - /// <summary>Cached delegate used with ExecutionContext.Run.</summary> - private static ContextCallback s_invokeMoveNext; // lazily-initialized due to SecurityCritical attribution - - /// <summary>Invokes the MoveNext method on the supplied IAsyncStateMachine.</summary> - /// <param name="stateMachine">The IAsyncStateMachine machine instance.</param> - private static void InvokeMoveNext(object stateMachine) - { - ((IAsyncStateMachine)stateMachine).MoveNext(); - } + protected static readonly ContextCallback InvokeMoveNextCallback = sm => ((IAsyncStateMachine)sm).MoveNext(); } /// <summary> diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/CompilationRelaxations.cs b/src/mscorlib/src/System/Runtime/CompilerServices/CompilationRelaxations.cs index 5e4f19410b..c3679b610c 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/CompilationRelaxations.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/CompilationRelaxations.cs @@ -13,7 +13,6 @@ namespace System.Runtime.CompilerServices /// IMPORTANT: Keep this in sync with corhdr.h [Serializable] [Flags] -[System.Runtime.InteropServices.ComVisible(true)] public enum CompilationRelaxations : int { NoStringInterning = 0x0008, // Start in 0x0008, we had other non public flags in this enum before, @@ -23,7 +22,6 @@ namespace System.Runtime.CompilerServices [Serializable] [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Method)] -[System.Runtime.InteropServices.ComVisible(true)] public class CompilationRelaxationsAttribute : Attribute { private int m_relaxations; // The relaxations. diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute.cs index 65755f6baa..1cd830cfca 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/CompilerGlobalScopeAttribute.cs @@ -18,7 +18,6 @@ namespace System.Runtime.CompilerServices { [Serializable] [AttributeUsage(AttributeTargets.Class)] - [System.Runtime.InteropServices.ComVisible(true)] public class CompilerGlobalScopeAttribute : Attribute { public CompilerGlobalScopeAttribute () {} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs index 74559673bb..4b2648ba6f 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs @@ -46,7 +46,6 @@ ** expose the full public surface area. ** ** -** ** Thread safety guarantees: ** ** ConditionalWeakTable is fully thread-safe and requires no @@ -60,6 +59,7 @@ ** may be delayed until appdomain shutdown. ===========================================================*/ +using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; @@ -67,8 +67,7 @@ using System.Threading; namespace System.Runtime.CompilerServices { #region ConditionalWeakTable - [ComVisible(false)] - public sealed class ConditionalWeakTable<TKey, TValue> + public sealed class ConditionalWeakTable<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>> where TKey : class where TValue : class { @@ -76,6 +75,7 @@ namespace System.Runtime.CompilerServices private const int InitialCapacity = 8; // Initial length of the table. Must be a power of two. private readonly object _lock; // This lock protects all mutation of data in the table. Readers do not take this lock. private volatile Container _container; // The actual storage for the table; swapped out as the table grows. + private int _activeEnumeratorRefCount; // The number of outstanding enumerators on the table #endregion #region Constructors @@ -190,6 +190,34 @@ namespace System.Runtime.CompilerServices } } + //-------------------------------------------------------------------------------------------- + // Clear all the key/value pairs + //-------------------------------------------------------------------------------------------- + public void Clear() + { + lock (_lock) + { + // To clear, we would prefer to simply drop the existing container + // and replace it with an empty one, as that's overall more efficient. + // However, if there are any active enumerators, we don't want to do + // that as it will end up removing all of the existing entries and + // allowing new items to be added at the same indices when the container + // is filled and replaced, and one of the guarantees we try to make with + // enumeration is that new items added after enumeration starts won't be + // included in the enumeration. As such, if there are active enumerators, + // we simply use the container's removal functionality to remove all of the + // keys; then when the table is resized, if there are still active enumerators, + // these empty slots will be maintained. + if (_activeEnumeratorRefCount > 0) + { + _container.RemoveAllKeys(); + } + else + { + _container = new Container(this); + } + } + } //-------------------------------------------------------------------------------------------- // key: key of the value to find. Cannot be null. @@ -256,6 +284,148 @@ namespace System.Runtime.CompilerServices public delegate TValue CreateValueCallback(TKey key); + //-------------------------------------------------------------------------------------------- + // Gets an enumerator for the table. The returned enumerator will not extend the lifetime of + // any object pairs in the table, other than the one that's Current. It will not return entries + // that have already been collected, nor will it return entries added after the enumerator was + // retrieved. It may not return all entries that were present when the enumerat was retrieved, + // however, such as not returning entries that were collected or removed after the enumerator + // was retrieved but before they were enumerated. + //-------------------------------------------------------------------------------------------- + IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() + { + lock (_lock) + { + Container c = _container; + return c == null || c.FirstFreeEntry == 0 ? + ((IEnumerable<KeyValuePair<TKey, TValue>>)Array.Empty<KeyValuePair<TKey, TValue>>()).GetEnumerator() : + new Enumerator(this); + } + } + + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<KeyValuePair<TKey, TValue>>)this).GetEnumerator(); + + /// <summary>Provides an enumerator for the table.</summary> + private sealed class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>> + { + // The enumerator would ideally hold a reference to the Container and the end index within that + // container. However, the safety of the CWT depends on the only reference to the Container being + // from the CWT itself; the Container then employs a two-phase finalization scheme, where the first + // phase nulls out that parent CWT's reference, guaranteeing that the second time it's finalized there + // can be no other existing references to it in use that would allow for concurrent usage of the + // native handles with finalization. We would break that if we allowed this Enumerator to hold a + // reference to the Container. Instead, the Enumerator holds a reference to the CWT rather than to + // the Container, and it maintains the CWT._activeEnumeratorRefCount field to track whether there + // are outstanding enumerators that have yet to be disposed/finalized. If there aren't any, the CWT + // behaves as it normally does. If there are, certain operations are affected, in particular resizes. + // Normally when the CWT is resized, it enumerates the contents of the table looking for indices that + // contain entries which have been collected or removed, and it frees those up, effectively moving + // down all subsequent entries in the container (not in the existing container, but in a replacement). + // This, however, would cause the enumerator's understanding of indices to break. So, as long as + // there is any outstanding enumerator, no compaction is performed. + + private ConditionalWeakTable<TKey, TValue> _table; // parent table, set to null when disposed + private readonly int _maxIndexInclusive; // last index in the container that should be enumerated + private int _currentIndex = -1; // the current index into the container + private KeyValuePair<TKey, TValue> _current; // the current entry set by MoveNext and returned from Current + + public Enumerator(ConditionalWeakTable<TKey, TValue> table) + { + Debug.Assert(table != null, "Must provide a valid table"); + Debug.Assert(Monitor.IsEntered(table._lock), "Must hold the _lock lock to construct the enumerator"); + Debug.Assert(table._container != null, "Should not be used on a finalized table"); + Debug.Assert(table._container.FirstFreeEntry > 0, "Should have returned an empty enumerator instead"); + + // Store a reference to the parent table and increase its active enumerator count. + _table = table; + Debug.Assert(table._activeEnumeratorRefCount >= 0, "Should never have a negative ref count before incrementing"); + table._activeEnumeratorRefCount++; + + // Store the max index to be enumerated. + _maxIndexInclusive = table._container.FirstFreeEntry - 1; + _currentIndex = -1; + } + + ~Enumerator() { Dispose(); } + + public void Dispose() + { + // Use an interlocked operation to ensure that only one thread can get access to + // the _table for disposal and thus only decrement the ref count once. + ConditionalWeakTable<TKey, TValue> table = Interlocked.Exchange(ref _table, null); + if (table != null) + { + // Ensure we don't keep the last current alive unnecessarily + _current = default(KeyValuePair<TKey, TValue>); + + // Decrement the ref count that was incremented when constructed + lock (table._lock) + { + table._activeEnumeratorRefCount--; + Debug.Assert(table._activeEnumeratorRefCount >= 0, "Should never have a negative ref count after decrementing"); + } + + // Finalization is purely to decrement the ref count. We can suppress it now. + GC.SuppressFinalize(this); + } + } + + public bool MoveNext() + { + // Start by getting the current table. If it's already been disposed, it will be null. + ConditionalWeakTable<TKey, TValue> table = _table; + if (table != null) + { + // Once have the table, we need to lock to synchronize with other operations on + // the table, like adding. + lock (table._lock) + { + // From the table, we have to get the current container. This could have changed + // since we grabbed the enumerator, but the index-to-pair mapping should not have + // due to there being at least one active enumerator. If the table (or rather its + // container at the time) has already been finalized, this will be null. + Container c = table._container; + if (c != null) + { + // We have the container. Find the next entry to return, if there is one. + // We need to loop as we may try to get an entry that's already been removed + // or collected, in which case we try again. + while (_currentIndex < _maxIndexInclusive) + { + _currentIndex++; + TKey key; + TValue value; + if (c.TryGetEntry(_currentIndex, out key, out value)) + { + _current = new KeyValuePair<TKey, TValue>(key, value); + return true; + } + } + } + } + } + + // Nothing more to enumerate. + return false; + } + + public KeyValuePair<TKey, TValue> Current + { + get + { + if (_currentIndex < 0) + { + ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); + } + return _current; + } + } + + object IEnumerator.Current => Current; + + public void Reset() { } + } + #endregion #region Internal members @@ -305,17 +475,6 @@ namespace System.Runtime.CompilerServices } } - //-------------------------------------------------------------------------------------------- - // Clear all the key/value pairs - //-------------------------------------------------------------------------------------------- - internal void Clear() - { - lock (_lock) - { - _container = new Container(this); - } - } - #endregion #region Private Members @@ -435,6 +594,8 @@ namespace System.Runtime.CompilerServices internal bool HasCapacity => _firstFreeEntry < _entries.Length; + internal int FirstFreeEntry => _firstFreeEntry; + //---------------------------------------------------------------------------------------- // Worker for adding a new key/value pair. // Preconditions: @@ -508,6 +669,44 @@ namespace System.Runtime.CompilerServices return -1; } + //---------------------------------------------------------------------------------------- + // Gets the entry at the specified entry index. + //---------------------------------------------------------------------------------------- + internal bool TryGetEntry(int index, out TKey key, out TValue value) + { + if (index < _entries.Length) + { + object oKey, oValue; + _entries[index].depHnd.GetPrimaryAndSecondary(out oKey, out oValue); + GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. + + if (oKey != null) + { + key = JitHelpers.UnsafeCast<TKey>(oKey); + value = JitHelpers.UnsafeCast<TValue>(oValue); + return true; + } + } + + key = default(TKey); + value = default(TValue); + return false; + } + + //---------------------------------------------------------------------------------------- + // Removes all of the keys in the table. + //---------------------------------------------------------------------------------------- + internal void RemoveAllKeys() + { + for (int i = 0; i < _firstFreeEntry; i++) + { + RemoveIndex(i); + } + } + + //---------------------------------------------------------------------------------------- + // Removes the specified key from the table, if it exists. + //---------------------------------------------------------------------------------------- internal bool Remove(TKey key) { VerifyIntegrity(); @@ -516,22 +715,27 @@ namespace System.Runtime.CompilerServices int entryIndex = FindEntry(key, out value); if (entryIndex != -1) { - ref Entry entry = ref _entries[entryIndex]; - - // We do not free the handle here, as we may be racing with readers who already saw the hash code. - // Instead, we simply overwrite the entry's hash code, so subsequent reads will ignore it. - // The handle will be free'd in Container's finalizer, after the table is resized or discarded. - Volatile.Write(ref entry.HashCode, -1); - - // Also, clear the key to allow GC to collect objects pointed to by the entry - entry.depHnd.SetPrimary(null); - + RemoveIndex(entryIndex); return true; } return false; } + private void RemoveIndex(int entryIndex) + { + Debug.Assert(entryIndex >= 0 && entryIndex < _firstFreeEntry); + + ref Entry entry = ref _entries[entryIndex]; + + // We do not free the handle here, as we may be racing with readers who already saw the hash code. + // Instead, we simply overwrite the entry's hash code, so subsequent reads will ignore it. + // The handle will be free'd in Container's finalizer, after the table is resized or discarded. + Volatile.Write(ref entry.HashCode, -1); + + // Also, clear the key to allow GC to collect objects pointed to by the entry + entry.depHnd.SetPrimary(null); + } internal void UpdateValue(int entryIndex, TValue newValue) { @@ -556,25 +760,33 @@ namespace System.Runtime.CompilerServices //---------------------------------------------------------------------------------------- internal Container Resize() { - // Start by assuming we won't resize. - int newSize = _buckets.Length; + Debug.Assert(!HasCapacity); - // If any expired or removed keys exist, we won't resize. bool hasExpiredEntries = false; - for (int entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) + int newSize = _buckets.Length; + + if (_parent == null || _parent._activeEnumeratorRefCount == 0) { - if (_entries[entriesIndex].HashCode == -1) + // If any expired or removed keys exist, we won't resize. + // If there any active enumerators, though, we don't want + // to compact and thus have no expired entries. + for (int entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) { - // the entry was removed - hasExpiredEntries = true; - break; - } + ref Entry entry = ref _entries[entriesIndex]; - if (_entries[entriesIndex].depHnd.IsAllocated && _entries[entriesIndex].depHnd.GetPrimary() == null) - { - // the entry has expired - hasExpiredEntries = true; - break; + if (entry.HashCode == -1) + { + // the entry was removed + hasExpiredEntries = true; + break; + } + + if (entry.depHnd.IsAllocated && entry.depHnd.GetPrimary() == null) + { + // the entry has expired + hasExpiredEntries = true; + break; + } } } @@ -585,44 +797,73 @@ namespace System.Runtime.CompilerServices } return Resize(newSize); - } + } internal Container Resize(int newSize) { + Debug.Assert(newSize >= _buckets.Length); Debug.Assert(IsPowerOfTwo(newSize)); // Reallocate both buckets and entries and rebuild the bucket and entries from scratch. // This serves both to scrub entries with expired keys and to put the new entries in the proper bucket. int[] newBuckets = new int[newSize]; - for (int bucketIndex = 0; bucketIndex < newSize; bucketIndex++) + for (int bucketIndex = 0; bucketIndex < newBuckets.Length; bucketIndex++) { newBuckets[bucketIndex] = -1; } Entry[] newEntries = new Entry[newSize]; int newEntriesIndex = 0; + bool activeEnumerators = _parent != null && _parent._activeEnumeratorRefCount > 0; // Migrate existing entries to the new table. - for (int entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) + if (activeEnumerators) { - int hashCode = _entries[entriesIndex].HashCode; - DependentHandle depHnd = _entries[entriesIndex].depHnd; - if (hashCode != -1 && depHnd.IsAllocated) + // There's at least one active enumerator, which means we don't want to + // remove any expired/removed entries, in order to not affect existing + // entries indices. Copy over the entries while rebuilding the buckets list, + // as the buckets are dependent on the buckets list length, which is changing. + for (; newEntriesIndex < _entries.Length; newEntriesIndex++) { - if (depHnd.GetPrimary() != null) - { - // Entry is used and has not expired. Link it into the appropriate bucket list. - newEntries[newEntriesIndex].HashCode = hashCode; - newEntries[newEntriesIndex].depHnd = depHnd; - int bucket = hashCode & (newBuckets.Length - 1); - newEntries[newEntriesIndex].Next = newBuckets[bucket]; - newBuckets[bucket] = newEntriesIndex; - newEntriesIndex++; - } - else + ref Entry oldEntry = ref _entries[newEntriesIndex]; + ref Entry newEntry = ref newEntries[newEntriesIndex]; + int hashCode = oldEntry.HashCode; + + newEntry.HashCode = hashCode; + newEntry.depHnd = oldEntry.depHnd; + int bucket = hashCode & (newBuckets.Length - 1); + newEntry.Next = newBuckets[bucket]; + newBuckets[bucket] = newEntriesIndex; + } + } + else + { + // There are no active enumerators, which means we want to compact by + // removing expired/removed entries. + for (int entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) + { + ref Entry oldEntry = ref _entries[entriesIndex]; + int hashCode = oldEntry.HashCode; + DependentHandle depHnd = oldEntry.depHnd; + if (hashCode != -1 && depHnd.IsAllocated) { - // Pretend the item was removed, so that this container's finalizer - // will clean up this dependent handle. - Volatile.Write(ref _entries[entriesIndex].HashCode, -1); + if (depHnd.GetPrimary() != null) + { + ref Entry newEntry = ref newEntries[newEntriesIndex]; + + // Entry is used and has not expired. Link it into the appropriate bucket list. + newEntry.HashCode = hashCode; + newEntry.depHnd = depHnd; + int bucket = hashCode & (newBuckets.Length - 1); + newEntry.Next = newBuckets[bucket]; + newBuckets[bucket] = newEntriesIndex; + newEntriesIndex++; + } + else + { + // Pretend the item was removed, so that this container's finalizer + // will clean up this dependent handle. + Volatile.Write(ref oldEntry.HashCode, -1); + } } } } @@ -632,6 +873,14 @@ namespace System.Runtime.CompilerServices // while the old container may still be in use. As such, we store a reference from the old container // to the new one, which will keep the new container alive as long as the old one is. var newContainer = new Container(_parent, newBuckets, newEntries, newEntriesIndex); + if (activeEnumerators) + { + // If there are active enumerators, both the old container and the new container may be storing + // the same entries with -1 hash codes, which the finalizer will clean up even if the container + // is not the active container for the table. To prevent that, we want to stop the old container + // from being finalized, as it no longer has any responsibility for any cleanup. + GC.SuppressFinalize(this); + } _oldKeepAlive = newContainer; // once this is set, the old container's finalizer will not free transferred dependent handles GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. @@ -815,7 +1064,6 @@ namespace System.Runtime.CompilerServices // This struct intentionally does no self-synchronization. It's up to the caller to // to use DependentHandles in a thread-safe way. //========================================================================================= - [ComVisible(false)] internal struct DependentHandle { #region Constructors diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/CustomConstantAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/CustomConstantAttribute.cs index c912095bda..1a5dcfdc11 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/CustomConstantAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/CustomConstantAttribute.cs @@ -9,7 +9,6 @@ namespace System.Runtime.CompilerServices { [Serializable] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter, Inherited=false)] - [System.Runtime.InteropServices.ComVisible(true)] public abstract class CustomConstantAttribute : Attribute { public abstract Object Value { get; } diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs index 4362aa84a1..148d916be1 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs @@ -9,7 +9,6 @@ namespace System.Runtime.CompilerServices { [Serializable] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter, Inherited=false)] - [System.Runtime.InteropServices.ComVisible(true)] public sealed class DateTimeConstantAttribute : CustomConstantAttribute { public DateTimeConstantAttribute(long ticks) diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs index 7bfaa7aafd..f05191840d 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs @@ -14,7 +14,6 @@ namespace System.Runtime.CompilerServices { [Serializable] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter, Inherited=false)] - [System.Runtime.InteropServices.ComVisible(true)] public sealed class DecimalConstantAttribute : Attribute { [CLSCompliant(false)] diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/DecoratedNameAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/DecoratedNameAttribute.cs deleted file mode 100644 index 75558d4e7e..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/DecoratedNameAttribute.cs +++ /dev/null @@ -1,18 +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; -using System.Runtime.InteropServices; - -namespace System.Runtime.CompilerServices -{ - [AttributeUsage(AttributeTargets.All), - ComVisible(false)] - internal sealed class DecoratedNameAttribute : Attribute - { - public DecoratedNameAttribute(string decoratedName) - {} - } -} - diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/DiscardableAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/DiscardableAttribute.cs index 303151f576..3fda4624d4 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/DiscardableAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/DiscardableAttribute.cs @@ -9,7 +9,6 @@ namespace System.Runtime.CompilerServices { using System; // Custom attribute to indicating a TypeDef is a discardable attribute -[System.Runtime.InteropServices.ComVisible(true)] public class DiscardableAttribute : Attribute { public DiscardableAttribute() diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/ITuple.cs b/src/mscorlib/src/System/Runtime/CompilerServices/ITuple.cs new file mode 100644 index 0000000000..cafee11f8a --- /dev/null +++ b/src/mscorlib/src/System/Runtime/CompilerServices/ITuple.cs @@ -0,0 +1,22 @@ +// 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. + +namespace System.Runtime.CompilerServices +{ + /// <summary> + /// This interface is required for types that want to be indexed into by dynamic patterns. + /// </summary> + public interface ITuple + { + /// <summary> + /// The number of positions in this data structure. + /// </summary> + int Length { get; } + + /// <summary> + /// Get the element at position <param name="index"/>. + /// </summary> + object this[int index] { get; } + } +} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IndexerNameAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IndexerNameAttribute.cs index 0323fe0cf6..c32be6f3a2 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IndexerNameAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/IndexerNameAttribute.cs @@ -8,7 +8,6 @@ namespace System.Runtime.CompilerServices [Serializable] [AttributeUsage(AttributeTargets.Property, Inherited = true)] -[System.Runtime.InteropServices.ComVisible(true)] public sealed class IndexerNameAttribute: Attribute { public IndexerNameAttribute(String indexerName) diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsVolatile.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsVolatile.cs index ea2fe032c6..5287e82b7b 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsVolatile.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/IsVolatile.cs @@ -4,7 +4,6 @@ namespace System.Runtime.CompilerServices { -[System.Runtime.InteropServices.ComVisible(true)] public static class IsVolatile { // no instantiation, please! diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/MethodImplAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/MethodImplAttribute.cs index d081d70070..b4991110f8 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/MethodImplAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/MethodImplAttribute.cs @@ -12,7 +12,6 @@ namespace System.Runtime.CompilerServices { [Serializable] [Flags] -[System.Runtime.InteropServices.ComVisible(true)] public enum MethodImplOptions { Unmanaged = System.Reflection.MethodImplAttributes.Unmanaged, @@ -21,14 +20,12 @@ namespace System.Runtime.CompilerServices { InternalCall = System.Reflection.MethodImplAttributes.InternalCall, Synchronized = System.Reflection.MethodImplAttributes.Synchronized, NoInlining = System.Reflection.MethodImplAttributes.NoInlining, - [System.Runtime.InteropServices.ComVisible(false)] AggressiveInlining = System.Reflection.MethodImplAttributes.AggressiveInlining, NoOptimization = System.Reflection.MethodImplAttributes.NoOptimization, // **** If you add something, update internal MethodImplAttribute(MethodImplAttributes methodImplAttributes)! **** } [Serializable] -[System.Runtime.InteropServices.ComVisible(true)] public enum MethodCodeType { IL = System.Reflection.MethodImplAttributes.IL, @@ -41,7 +38,6 @@ namespace System.Runtime.CompilerServices { // Custom attribute to specify additional method properties. [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false)] -[System.Runtime.InteropServices.ComVisible(true)] sealed public class MethodImplAttribute : Attribute { internal MethodImplOptions _val; diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index 926eb6c3cb..509e527ecb 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -18,7 +18,6 @@ namespace System.Runtime.CompilerServices { using System.Runtime.InteropServices; using System.Runtime.ConstrainedExecution; using System.Runtime.Serialization; - using System.Security.Permissions; using System.Threading; using System.Runtime.Versioning; using System.Diagnostics.Contracts; @@ -131,7 +130,6 @@ namespace System.Runtime.CompilerServices { // Note: this method is not part of the CER support, and is not to be confused with ProbeForSufficientStack // below. [MethodImplAttribute(MethodImplOptions.InternalCall)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static extern void EnsureSufficientExecutionStack(); // This method ensures that there is sufficient stack to execute the average Framework function. @@ -139,7 +137,6 @@ namespace System.Runtime.CompilerServices { // Note: this method is not part of the CER support, and is not to be confused with ProbeForSufficientStack // below. [MethodImplAttribute(MethodImplOptions.InternalCall)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static extern bool TryEnsureSufficientExecutionStack(); public static void ProbeForSufficientStack() @@ -148,7 +145,6 @@ namespace System.Runtime.CompilerServices { // This method is a marker placed immediately before a try clause to mark the corresponding catch and finally blocks as // constrained. There's no code here other than the probe because most of the work is done at JIT time when we spot a call to this routine. - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void PrepareConstrainedRegions() { ProbeForSufficientStack(); @@ -156,7 +152,6 @@ namespace System.Runtime.CompilerServices { // When we detect a CER with no calls, we can point the JIT to this non-probing version instead // as we don't need to probe. - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void PrepareConstrainedRegionsNoOP() { } @@ -168,7 +163,6 @@ namespace System.Runtime.CompilerServices { [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern void ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData); - [PrePrepareMethod] internal static void ExecuteBackoutCodeHelper(Object backoutCode, Object userData, bool exceptionThrown) { ((CleanupCode)backoutCode)(userData, exceptionThrown); diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs index d2691df6b9..e3b2d2ce62 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs @@ -15,7 +15,6 @@ namespace System.Runtime.CompilerServices { using System; using System.Runtime.Serialization; using System.Runtime.Remoting; - using System.Security.Permissions; using System.Diagnostics.Contracts; [Serializable] diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs index 98a81ea470..f01900a5bf 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs @@ -44,7 +44,6 @@ using System.Diagnostics.Contracts; using System.Security; using System.Threading; using System.Threading.Tasks; -using System.Security.Permissions; using System.Diagnostics.Tracing; // NOTE: For performance reasons, initialization is not verified. If a developer @@ -198,21 +197,19 @@ namespace System.Runtime.CompilerServices /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception> /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, bool flowExecutionContext) { if (continuation == null) throw new ArgumentNullException(nameof(continuation)); - StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; // If TaskWait* ETW events are enabled, trace a beginning event for this await // and set up an ending event to be traced when the asynchronous await completes. - if ( TplEtwProvider.Log.IsEnabled() || Task.s_asyncDebuggingEnabled) + if (TplEtwProvider.Log.IsEnabled() || Task.s_asyncDebuggingEnabled) { continuation = OutputWaitEtwEvents(task, continuation); } // Set the continuation onto the awaited task. - task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext, ref stackMark); + task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext); } /// <summary> @@ -244,7 +241,7 @@ namespace System.Runtime.CompilerServices (currentTaskAtBegin != null ? currentTaskAtBegin.m_taskScheduler.Id : TaskScheduler.Default.Id), (currentTaskAtBegin != null ? currentTaskAtBegin.Id : 0), task.Id, TplEtwProvider.TaskWaitBehavior.Asynchronous, - (continuationTask != null ? continuationTask.Id : 0), System.Threading.Thread.GetDomainID()); + (continuationTask != null ? continuationTask.Id : 0)); } // Create a continuation action that outputs the end event and then invokes the user diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TupleElementNamesAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TupleElementNamesAttribute.cs new file mode 100644 index 0000000000..65b120e6b4 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/CompilerServices/TupleElementNamesAttribute.cs @@ -0,0 +1,57 @@ +// 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.Collections.Generic; + +namespace System.Runtime.CompilerServices +{ + /// <summary> + /// Indicates that the use of <see cref="System.ValueTuple"/> on a member is meant to be treated as a tuple with element names. + /// </summary> + [CLSCompliant(false)] + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Event)] + public sealed class TupleElementNamesAttribute : Attribute + { + private readonly string[] _transformNames; + + /// <summary> + /// Initializes a new instance of the <see + /// cref="TupleElementNamesAttribute"/> class. + /// </summary> + /// <param name="transformNames"> + /// Specifies, in a pre-order depth-first traversal of a type's + /// construction, which <see cref="System.ValueType"/> occurrences are + /// meant to carry element names. + /// </param> + /// <remarks> + /// This constructor is meant to be used on types that contain an + /// instantiation of <see cref="System.ValueType"/> that contains + /// element names. For instance, if <c>C</c> is a generic type with + /// two type parameters, then a use of the constructed type <c>C{<see + /// cref="System.ValueTuple{T1, T2}"/>, <see + /// cref="System.ValueTuple{T1, T2, T3}"/></c> might be intended to + /// treat the first type argument as a tuple with element names and the + /// second as a tuple without element names. In which case, the + /// appropriate attribute specification should use a + /// <c>transformNames</c> value of <c>{ "name1", "name2", null, null, + /// null }</c>. + /// </remarks> + public TupleElementNamesAttribute(string[] transformNames) + { + if (transformNames == null) + { + throw new ArgumentNullException(nameof(transformNames)); + } + + _transformNames = transformNames; + } + + /// <summary> + /// Specifies, in a pre-order depth-first traversal of a type's + /// construction, which <see cref="System.ValueTuple"/> elements are + /// meant to carry element names. + /// </summary> + public IList<string> TransformNames => _transformNames; + } +}
\ No newline at end of file diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs index d9e067bd4c..147c103047 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs @@ -26,18 +26,6 @@ namespace System.Runtime.CompilerServices } } - internal static TypeForwardedToAttribute[] GetCustomAttribute(RuntimeAssembly assembly) - { - Type[] types = null; - RuntimeAssembly.GetForwardedTypes(assembly.GetNativeHandle(), JitHelpers.GetObjectHandleOnStack(ref types)); - - TypeForwardedToAttribute[] attributes = new TypeForwardedToAttribute[types.Length]; - for (int i = 0; i < types.Length; ++i) - attributes[i] = new TypeForwardedToAttribute(types[i]); - - return attributes; - } - } } diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs index b212f4555b..adfa015161 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -76,5 +76,18 @@ namespace System.Runtime.CompilerServices // See getILIntrinsicImplementationForUnsafe for how this happens. throw new InvalidOperationException(); } + + /// <summary> + /// Initializes a block of memory at the given location with a given initial value + /// without assuming architecture dependent alignment of the address. + /// </summary> + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void InitBlockUnaligned(ref byte startAddress, byte value, uint byteCount) + { + // The body of this function will be replaced by the EE with unsafe code!!! + // See getILIntrinsicImplementationForUnsafe for how this happens. + throw new InvalidOperationException(); + } } } diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/YieldAwaitable.cs b/src/mscorlib/src/System/Runtime/CompilerServices/YieldAwaitable.cs index 86789bf12d..92d1b4f95b 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/YieldAwaitable.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/YieldAwaitable.cs @@ -28,7 +28,6 @@ using System.Diagnostics.Contracts; using System.Diagnostics.Tracing; using System.Threading; using System.Threading.Tasks; -using System.Security.Permissions; namespace System.Runtime.CompilerServices { diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs index c1346f7527..080e42f46f 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs @@ -216,7 +216,6 @@ namespace System.Runtime.CompilerServices { extern static bool IsAddressInStack(IntPtr ptr); #endif -#if FEATURE_SPAN_OF_T static internal bool ByRefLessThan<T>(ref T refA, ref T refB) { // The body of this function will be replaced by the EE with unsafe code!!! @@ -239,6 +238,5 @@ namespace System.Runtime.CompilerServices { typeof(ArrayPinningHelper).ToString(); // Type used by the actual method body throw new InvalidOperationException(); } -#endif // FEATURE_SPAN_OF_T } } |