diff options
author | Jiyoung Yun <jy910.yun@samsung.com> | 2016-12-27 16:46:08 +0900 |
---|---|---|
committer | Jiyoung Yun <jy910.yun@samsung.com> | 2016-12-27 16:46:08 +0900 |
commit | db20f3f1bb8595633a7e16c8900fd401a453a6b5 (patch) | |
tree | e5435159cd1bf0519276363a6fe1663d1721bed3 /src/mscorlib/src/System/Runtime/CompilerServices | |
parent | 4b4aad7217d3292650e77eec2cf4c198ea9c3b4b (diff) | |
download | coreclr-db20f3f1bb8595633a7e16c8900fd401a453a6b5.tar.gz coreclr-db20f3f1bb8595633a7e16c8900fd401a453a6b5.tar.bz2 coreclr-db20f3f1bb8595633a7e16c8900fd401a453a6b5.zip |
Imported Upstream version 1.0.0.9127upstream/1.0.0.9127
Diffstat (limited to 'src/mscorlib/src/System/Runtime/CompilerServices')
32 files changed, 667 insertions, 878 deletions
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs index 05850605b8..6a16462383 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs @@ -32,7 +32,6 @@ namespace System.Runtime.CompilerServices /// Provides a builder for asynchronous methods that return void. /// This type is intended for compiler use only. /// </summary> - [HostProtection(Synchronization = true, ExternalThreading = true)] public struct AsyncVoidMethodBuilder { /// <summary>The synchronization context associated with this operation.</summary> @@ -59,14 +58,13 @@ namespace System.Runtime.CompilerServices /// <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 was null (Nothing in Visual Basic).</exception> - [SecuritySafeCritical] [DebuggerStepThrough] public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { // See comment on AsyncMethodBuilderCore.Start // AsyncMethodBuilderCore.Start(ref stateMachine); - if (stateMachine == null) throw new ArgumentNullException("stateMachine"); + if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine)); Contract.EndContractBlock(); // Run the MoveNext method within a copy-on-write ExecutionContext scope. @@ -112,7 +110,7 @@ namespace System.Runtime.CompilerServices { AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null; var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize); - Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action."); + Debug.Assert(continuation != null, "GetCompletionAction should always return a valid action."); // If this is our first await, such that we've not yet boxed the state machine, do so now. if (m_coreState.m_stateMachine == null) @@ -149,7 +147,6 @@ namespace System.Runtime.CompilerServices /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam> /// <param name="awaiter">The awaiter.</param> /// <param name="stateMachine">The state machine.</param> - [SecuritySafeCritical] public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion @@ -159,7 +156,7 @@ namespace System.Runtime.CompilerServices { AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null; var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize); - Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action."); + Debug.Assert(continuation != null, "GetCompletionAction should always return a valid action."); // If this is our first await, such that we've not yet boxed the state machine, do so now. if (m_coreState.m_stateMachine == null) @@ -200,7 +197,7 @@ namespace System.Runtime.CompilerServices /// <exception cref="System.InvalidOperationException">The builder is not initialized.</exception> public void SetException(Exception exception) { - if (exception == null) throw new ArgumentNullException("exception"); + if (exception == null) throw new ArgumentNullException(nameof(exception)); Contract.EndContractBlock(); if (AsyncCausalityTracer.LoggingOn) @@ -231,7 +228,7 @@ namespace System.Runtime.CompilerServices /// <summary>Notifies the current synchronization context that the operation completed.</summary> private void NotifySynchronizationContextOfCompletion() { - Contract.Assert(m_synchronizationContext != null, "Must only be used with a non-null context."); + Debug.Assert(m_synchronizationContext != null, "Must only be used with a non-null context."); try { m_synchronizationContext.OperationCompleted(); @@ -273,7 +270,6 @@ namespace System.Runtime.CompilerServices /// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed, /// or else the copies may end up building distinct Task instances. /// </remarks> - [HostProtection(Synchronization = true, ExternalThreading = true)] public struct AsyncTaskMethodBuilder { /// <summary>A cached VoidTaskResult task used for builders that complete synchronously.</summary> @@ -294,14 +290,13 @@ namespace System.Runtime.CompilerServices /// <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> - [SecuritySafeCritical] [DebuggerStepThrough] public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { // See comment on AsyncMethodBuilderCore.Start // AsyncMethodBuilderCore.Start(ref stateMachine); - if (stateMachine == null) throw new ArgumentNullException("stateMachine"); + if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine)); Contract.EndContractBlock(); // Run the MoveNext method within a copy-on-write ExecutionContext scope. @@ -421,7 +416,6 @@ namespace System.Runtime.CompilerServices /// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed, /// or else the copies may end up building distinct Task instances. /// </remarks> - [HostProtection(Synchronization = true, ExternalThreading = true)] public struct AsyncTaskMethodBuilder<TResult> { /// <summary>A cached task for default(TResult).</summary> @@ -450,14 +444,13 @@ namespace System.Runtime.CompilerServices /// <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> - [SecuritySafeCritical] [DebuggerStepThrough] public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { // See comment on AsyncMethodBuilderCore.Start // AsyncMethodBuilderCore.Start(ref stateMachine); - if (stateMachine == null) throw new ArgumentNullException("stateMachine"); + if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine)); Contract.EndContractBlock(); // Run the MoveNext method within a copy-on-write ExecutionContext scope. @@ -503,7 +496,7 @@ namespace System.Runtime.CompilerServices { AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null; var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize); - Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action."); + Debug.Assert(continuation != null, "GetCompletionAction should always return a valid action."); // If this is our first await, such that we've not yet boxed the state machine, do so now. if (m_coreState.m_stateMachine == null) @@ -534,7 +527,6 @@ namespace System.Runtime.CompilerServices /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam> /// <param name="awaiter">The awaiter.</param> /// <param name="stateMachine">The state machine.</param> - [SecuritySafeCritical] public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion @@ -544,7 +536,7 @@ namespace System.Runtime.CompilerServices { AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null; var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize); - Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action."); + Debug.Assert(continuation != null, "GetCompletionAction should always return a valid action."); // If this is our first await, such that we've not yet boxed the state machine, do so now. if (m_coreState.m_stateMachine == null) @@ -595,7 +587,7 @@ namespace System.Runtime.CompilerServices if (task == null) { m_task = GetTaskForResult(result); - Contract.Assert(m_task != null, "GetTaskForResult should never return null"); + Debug.Assert(m_task != null, "GetTaskForResult should never return null"); } // Slow path: complete the existing task. else @@ -650,7 +642,7 @@ namespace System.Runtime.CompilerServices /// <exception cref="System.InvalidOperationException">The task has already completed.</exception> public void SetException(Exception exception) { - if (exception == null) throw new ArgumentNullException("exception"); + if (exception == null) throw new ArgumentNullException(nameof(exception)); Contract.EndContractBlock(); @@ -713,7 +705,6 @@ namespace System.Runtime.CompilerServices /// </summary> /// <param name="result">The result for which we need a task.</param> /// <returns>The completed task containing the result.</returns> - [SecuritySafeCritical] // for JitHelpers.UnsafeCast private Task<TResult> GetTaskForResult(TResult result) { Contract.Ensures( @@ -819,7 +810,7 @@ namespace System.Runtime.CompilerServices /// <summary>Creates an array of cached tasks for the values in the range [INCLUSIVE_MIN,EXCLUSIVE_MAX).</summary> private static Task<Int32>[] CreateInt32Tasks() { - Contract.Assert(EXCLUSIVE_INT32_MAX >= INCLUSIVE_INT32_MIN, "Expected max to be at least min"); + Debug.Assert(EXCLUSIVE_INT32_MAX >= INCLUSIVE_INT32_MIN, "Expected max to be at least min"); var tasks = new Task<Int32>[EXCLUSIVE_INT32_MAX - INCLUSIVE_INT32_MIN]; for (int i = 0; i < tasks.Length; i++) { @@ -854,12 +845,11 @@ namespace System.Runtime.CompilerServices /// <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> - [SecuritySafeCritical] [DebuggerStepThrough] internal static void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { - if (stateMachine == null) throw new ArgumentNullException("stateMachine"); + if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine)); Contract.EndContractBlock(); // Run the MoveNext method within a copy-on-write ExecutionContext scope. @@ -887,7 +877,7 @@ namespace System.Runtime.CompilerServices /// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception> public void SetStateMachine(IAsyncStateMachine stateMachine) { - if (stateMachine == null) throw new ArgumentNullException("stateMachine"); + if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine)); Contract.EndContractBlock(); if (m_stateMachine != null) throw new InvalidOperationException(Environment.GetResourceString("AsyncMethodBuilder_InstanceNotInitialized")); m_stateMachine = stateMachine; @@ -902,10 +892,9 @@ namespace System.Runtime.CompilerServices /// <param name="builder">The builder.</param> /// <param name="stateMachine">The state machine.</param> /// <returns>An Action to provide to the awaiter.</returns> - [SecuritySafeCritical] internal Action GetCompletionAction(Task taskForTracing, ref MoveNextRunner runnerToInitialize) { - Contract.Assert(m_defaultContextAction == null || m_stateMachine != null, + Debug.Assert(m_defaultContextAction == null || m_stateMachine != null, "Expected non-null m_stateMachine on non-null m_defaultContextAction"); // Alert a listening debugger that we can't make forward progress unless it slips threads. @@ -928,7 +917,7 @@ namespace System.Runtime.CompilerServices action = m_defaultContextAction; if (action != null) { - Contract.Assert(m_stateMachine != null, "If the delegate was set, the state machine should have been as well."); + Debug.Assert(m_stateMachine != null, "If the delegate was set, the state machine should have been as well."); return action; } @@ -994,8 +983,8 @@ namespace System.Runtime.CompilerServices m_stateMachine = stateMachine; m_stateMachine.SetStateMachine(m_stateMachine); - Contract.Assert(runner.m_stateMachine == null, "The runner's state machine should not yet have been populated."); - Contract.Assert(m_stateMachine != null, "The builder's state machine field should have been initialized."); + Debug.Assert(runner.m_stateMachine == null, "The runner's state machine should not yet have been populated."); + Debug.Assert(m_stateMachine != null, "The builder's state machine field should have been initialized."); // Now that we have the state machine, store it into the runner that the action delegate points to. // And return the action. @@ -1045,17 +1034,15 @@ namespace System.Runtime.CompilerServices /// <summary>Initializes the runner.</summary> /// <param name="context">The context with which to run MoveNext.</param> - [SecurityCritical] // Run needs to be SSC to map to Action delegate, so to prevent misuse, we only allow construction through SC internal MoveNextRunnerWithContext(ExecutionContext context, IAsyncStateMachine stateMachine) : base(stateMachine) { m_context = context; } /// <summary>Invokes MoveNext under the provided context.</summary> - [SecuritySafeCritical] internal void RunWithCapturedContext() { - Contract.Assert(m_stateMachine != null, "The state machine must have been set before calling Run."); + Debug.Assert(m_stateMachine != null, "The state machine must have been set before calling Run."); if (m_context != null) { @@ -1080,34 +1067,29 @@ namespace System.Runtime.CompilerServices internal IAsyncStateMachine m_stateMachine; /// <summary>Initializes the runner.</summary> - [SecurityCritical] // Run needs to be SSC to map to Action delegate, so to prevent misuse, we only allow construction through SC internal MoveNextRunner(IAsyncStateMachine stateMachine) { m_stateMachine = stateMachine; } /// <summary>Invokes MoveNext under the default context.</summary> - [SecuritySafeCritical] internal void RunWithDefaultContext() { - Contract.Assert(m_stateMachine != null, "The state machine must have been set before calling Run."); + Debug.Assert(m_stateMachine != null, "The state machine must have been set before calling Run."); ExecutionContext.Run(ExecutionContext.PreAllocatedDefault, InvokeMoveNextCallback, m_stateMachine, preserveSyncCtx: true); } /// <summary>Gets a delegate to the InvokeMoveNext method.</summary> protected static ContextCallback InvokeMoveNextCallback { - [SecuritySafeCritical] get { return s_invokeMoveNext ?? (s_invokeMoveNext = InvokeMoveNext); } } /// <summary>Cached delegate used with ExecutionContext.Run.</summary> - [SecurityCritical] 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> - [SecurityCritical] // necessary for ContextCallback in CoreCLR private static void InvokeMoveNext(object stateMachine) { ((IAsyncStateMachine)stateMachine).MoveNext(); diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/CallingConvention.cs b/src/mscorlib/src/System/Runtime/CompilerServices/CallingConvention.cs deleted file mode 100644 index f44251d480..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/CallingConvention.cs +++ /dev/null @@ -1,30 +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 -{ - // Types used in Custom Modifier to specify calling conventions. - [System.Runtime.InteropServices.ComVisible(true)] - public class CallConvCdecl - { - } - - [System.Runtime.InteropServices.ComVisible(true)] - public class CallConvStdcall - { - } - - [System.Runtime.InteropServices.ComVisible(true)] - public class CallConvThiscall - { - } - - [System.Runtime.InteropServices.ComVisible(true)] - public class CallConvFastcall - { - } - -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs index 21d677241d..74559673bb 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs @@ -60,31 +60,29 @@ ** may be delayed until appdomain shutdown. ===========================================================*/ +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; + namespace System.Runtime.CompilerServices { - using System; - using System.Collections.Generic; - using System.Runtime.Versioning; - using System.Runtime.InteropServices; - - #region ConditionalWeakTable - [System.Runtime.InteropServices.ComVisible(false)] + [ComVisible(false)] public sealed class ConditionalWeakTable<TKey, TValue> where TKey : class where TValue : class { + #region Fields + 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. + #endregion #region Constructors - [System.Security.SecuritySafeCritical] public ConditionalWeakTable() { - _buckets = Array.Empty<int>(); - _entries = Array.Empty<Entry>(); - _freeList = -1; - _lock = new Object(); - - Resize(); // Resize at once (so won't need "if initialized" checks all over) + _lock = new object(); + _container = new Container(this); } #endregion @@ -99,18 +97,14 @@ namespace System.Runtime.CompilerServices // Note: The key may get garbaged collected during the TryGetValue operation. If so, TryGetValue // may at its discretion, return "false" and set "value" to the default (as if the key was not present.) //-------------------------------------------------------------------------------------------- - [System.Security.SecuritySafeCritical] public bool TryGetValue(TKey key, out TValue value) { if (key == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } - lock(_lock) - { - VerifyIntegrity(); - return TryGetValueWorker(key, out value); - } + + return _container.TryGetValueWorker(key, out value); } //-------------------------------------------------------------------------------------------- @@ -123,7 +117,6 @@ namespace System.Runtime.CompilerServices // has the right to consider any prior entries successfully removed and add a new entry without // throwing an exception. //-------------------------------------------------------------------------------------------- - [System.Security.SecuritySafeCritical] public void Add(TKey key, TValue value) { if (key == null) @@ -131,22 +124,48 @@ namespace System.Runtime.CompilerServices ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } - lock(_lock) + lock (_lock) { - VerifyIntegrity(); - _invalid = true; - - int entryIndex = FindEntry(key); + object otherValue; + int entryIndex = _container.FindEntry(key, out otherValue); if (entryIndex != -1) { - _invalid = false; ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate); } CreateEntry(key, value); - _invalid = false; } + } + + //-------------------------------------------------------------------------------------------- + // key: key to add or update. May not be null. + // value: value to associate with key. + // + // If the key is already entered into the dictionary, this method will update the value associated with key. + //-------------------------------------------------------------------------------------------- + public void AddOrUpdate(TKey key, TValue value) + { + if (key == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); + } + + lock (_lock) + { + object otherValue; + int entryIndex = _container.FindEntry(key, out otherValue); + + // if we found a key we should just update, if no we should create a new entry. + if (entryIndex != -1) + { + _container.UpdateValue(entryIndex, value); + } + else + { + CreateEntry(key, value); + } + } } //-------------------------------------------------------------------------------------------- @@ -156,9 +175,8 @@ namespace System.Runtime.CompilerServices // // Note: The key may get garbage collected during the Remove() operation. If so, // Remove() will not fail or throw, however, the return value can be either true or false - // depending on the race condition. + // depending on who wins the race. //-------------------------------------------------------------------------------------------- - [System.Security.SecuritySafeCritical] public bool Remove(TKey key) { if (key == null) @@ -166,40 +184,9 @@ namespace System.Runtime.CompilerServices ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); } - lock(_lock) + lock (_lock) { - VerifyIntegrity(); - _invalid = true; - - int hashCode = RuntimeHelpers.GetHashCode(key) & Int32.MaxValue; - int bucket = hashCode % _buckets.Length; - int last = -1; - for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].next) - { - if (_entries[entriesIndex].hashCode == hashCode && _entries[entriesIndex].depHnd.GetPrimary() == key) - { - if (last == -1) - { - _buckets[bucket] = _entries[entriesIndex].next; - } - else - { - _entries[last].next = _entries[entriesIndex].next; - } - - _entries[entriesIndex].depHnd.Free(); - _entries[entriesIndex].next = _freeList; - - _freeList = entriesIndex; - - _invalid = false; - return true; - - } - last = entriesIndex; - } - _invalid = false; - return false; + return _container.Remove(key); } } @@ -219,46 +206,39 @@ namespace System.Runtime.CompilerServices // This rule permits the table to invoke createValueCallback outside the internal table lock // to prevent deadlocks. //-------------------------------------------------------------------------------------------- - [System.Security.SecuritySafeCritical] public TValue GetValue(TKey key, CreateValueCallback createValueCallback) { - // Our call to TryGetValue() validates key so no need for us to. - // - // if (key == null) - // { - // ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); - // } + // key is validated by TryGetValue if (createValueCallback == null) { - throw new ArgumentNullException("createValueCallback"); + throw new ArgumentNullException(nameof(createValueCallback)); } TValue existingValue; - if (TryGetValue(key, out existingValue)) - { - return existingValue; - } + return TryGetValue(key, out existingValue) ? + existingValue : + GetValueLocked(key, createValueCallback); + } - // If we got here, the key is not currently in table. Invoke the callback (outside the lock) + private TValue GetValueLocked(TKey key, CreateValueCallback createValueCallback) + { + // If we got here, the key was not in the table. Invoke the callback (outside the lock) // to generate the new value for the key. TValue newValue = createValueCallback(key); - lock(_lock) + lock (_lock) { - VerifyIntegrity(); - _invalid = true; - - // Now that we've retaken the lock, must recheck in case there was a race condition to add the key. - if (TryGetValueWorker(key, out existingValue)) + // Now that we've taken the lock, must recheck in case we lost a race to add the key. + TValue existingValue; + if (_container.TryGetValueWorker(key, out existingValue)) { - _invalid = false; return existingValue; } else { + // Verified in-lock that we won the race to add the key. Add it now. CreateEntry(key, newValue); - _invalid = false; return newValue; } } @@ -271,17 +251,15 @@ namespace System.Runtime.CompilerServices // to create new instances as needed. If TValue does not have a default constructor, this will // throw. //-------------------------------------------------------------------------------------------- - public TValue GetOrCreateValue(TKey key) - { - return GetValue(key, k => Activator.CreateInstance<TValue>()); - } + + public TValue GetOrCreateValue(TKey key) => GetValue(key, _ => Activator.CreateInstance<TValue>()); public delegate TValue CreateValueCallback(TKey key); - + #endregion - #region internal members - + #region Internal members + //-------------------------------------------------------------------------------------------- // Find a key that equals (value equality) with the given key - don't use in perf critical path // Note that it calls out to Object.Equals which may calls the override version of Equals @@ -290,56 +268,26 @@ namespace System.Runtime.CompilerServices // if you know for sure that either you won't run into dead locks or you need to live with the // possiblity //-------------------------------------------------------------------------------------------- - [System.Security.SecuritySafeCritical] [FriendAccessAllowed] internal TKey FindEquivalentKeyUnsafe(TKey key, out TValue value) { lock (_lock) { - for (int bucket = 0; bucket < _buckets.Length; ++bucket) - { - for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].next) - { - object thisKey, thisValue; - _entries[entriesIndex].depHnd.GetPrimaryAndSecondary(out thisKey, out thisValue); - if (Object.Equals(thisKey, key)) - { - value = (TValue) thisValue; - return (TKey) thisKey; - } - } - } + return _container.FindEquivalentKeyUnsafe(key, out value); } - - value = default(TValue); - return null; } - + //-------------------------------------------------------------------------------------------- // Returns a collection of keys - don't use in perf critical path //-------------------------------------------------------------------------------------------- internal ICollection<TKey> Keys { - [System.Security.SecuritySafeCritical] get { - List<TKey> list = new List<TKey>(); lock (_lock) { - for (int bucket = 0; bucket < _buckets.Length; ++bucket) - { - for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].next) - { - TKey thisKey = (TKey) _entries[entriesIndex].depHnd.GetPrimary(); - if (thisKey != null) - { - list.Add(thisKey); - } - } - } + return _container.Keys; } - - return list; } } @@ -348,332 +296,500 @@ namespace System.Runtime.CompilerServices //-------------------------------------------------------------------------------------------- internal ICollection<TValue> Values { - [System.Security.SecuritySafeCritical] get { - List<TValue> list = new List<TValue>(); lock (_lock) { - for (int bucket = 0; bucket < _buckets.Length; ++bucket) - { - for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].next) - { - Object primary = null; - Object secondary = null; - - _entries[entriesIndex].depHnd.GetPrimaryAndSecondary(out primary, out secondary); - - // Now that we've secured a strong reference to the secondary, must check the primary again - // to ensure it didn't expire (otherwise, we open a race condition where TryGetValue misreports an - // expired key as a live key with a null value.) - if (primary != null) - { - list.Add((TValue)secondary); - } - } - } + return _container.Values; } - - return list; } } - + //-------------------------------------------------------------------------------------------- // Clear all the key/value pairs //-------------------------------------------------------------------------------------------- - [System.Security.SecuritySafeCritical] internal void Clear() { lock (_lock) { - // Clear the buckets - for (int bucketIndex = 0; bucketIndex < _buckets.Length; bucketIndex++) - { - _buckets[bucketIndex] = -1; - } - - // Clear the entries and link them backwards together as part of free list - int entriesIndex; - for (entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) - { - if (_entries[entriesIndex].depHnd.IsAllocated) - { - _entries[entriesIndex].depHnd.Free(); - } - - // Link back wards as free list - _entries[entriesIndex].next = entriesIndex - 1; - } - - _freeList = entriesIndex - 1; - } + _container = new Container(this); + } } #endregion - + #region Private Members - [System.Security.SecurityCritical] + //---------------------------------------------------------------------------------------- - // Worker for finding a key/value pair + // Worker for adding a new key/value pair. + // Will resize the container if it is full // // Preconditions: // Must hold _lock. - // Key already validated as non-null + // Key already validated as non-null and not already in table. //---------------------------------------------------------------------------------------- - private bool TryGetValueWorker(TKey key, out TValue value) + private void CreateEntry(TKey key, TValue value) { - int entryIndex = FindEntry(key); - if (entryIndex != -1) + Debug.Assert(Monitor.IsEntered(_lock)); + + Container c = _container; + if (!c.HasCapacity) { - Object primary = null; - Object secondary = null; - _entries[entryIndex].depHnd.GetPrimaryAndSecondary(out primary, out secondary); - // Now that we've secured a strong reference to the secondary, must check the primary again - // to ensure it didn't expire (otherwise, we open a race condition where TryGetValue misreports an - // expired key as a live key with a null value.) - if (primary != null) - { - value = (TValue)secondary; - return true; - } + _container = c = c.Resize(); } + c.CreateEntryNoResize(key, value); + } + + private static bool IsPowerOfTwo(int value) => (value > 0) && ((value & (value - 1)) == 0); - value = default(TValue); - return false; + #endregion + + #region Private Data Members + //-------------------------------------------------------------------------------------------- + // Entry can be in one of four states: + // + // - Unused (stored with an index _firstFreeEntry and above) + // depHnd.IsAllocated == false + // hashCode == <dontcare> + // next == <dontcare>) + // + // - Used with live key (linked into a bucket list where _buckets[hashCode & (_buckets.Length - 1)] points to first entry) + // depHnd.IsAllocated == true, depHnd.GetPrimary() != null + // hashCode == RuntimeHelpers.GetHashCode(depHnd.GetPrimary()) & Int32.MaxValue + // next links to next Entry in bucket. + // + // - Used with dead key (linked into a bucket list where _buckets[hashCode & (_buckets.Length - 1)] points to first entry) + // depHnd.IsAllocated == true, depHnd.GetPrimary() == null + // hashCode == <notcare> + // next links to next Entry in bucket. + // + // - Has been removed from the table (by a call to Remove) + // depHnd.IsAllocated == true, depHnd.GetPrimary() == <notcare> + // hashCode == -1 + // next links to next Entry in bucket. + // + // The only difference between "used with live key" and "used with dead key" is that + // depHnd.GetPrimary() returns null. The transition from "used with live key" to "used with dead key" + // happens asynchronously as a result of normal garbage collection. The dictionary itself + // receives no notification when this happens. + // + // When the dictionary grows the _entries table, it scours it for expired keys and does not + // add those to the new container. + //-------------------------------------------------------------------------------------------- + private struct Entry + { + public DependentHandle depHnd; // Holds key and value using a weak reference for the key and a strong reference + // for the value that is traversed only if the key is reachable without going through the value. + public int HashCode; // Cached copy of key's hashcode + public int Next; // Index of next entry, -1 if last } - //---------------------------------------------------------------------------------------- - // Worker for adding a new key/value pair. // - // Preconditions: - // Must hold _lock. - // Key already validated as non-null and not already in table. - //---------------------------------------------------------------------------------------- - [System.Security.SecurityCritical] - private void CreateEntry(TKey key, TValue value) + // Container holds the actual data for the table. A given instance of Container always has the same capacity. When we need + // more capacity, we create a new Container, copy the old one into the new one, and discard the old one. This helps enable lock-free + // reads from the table, as readers never need to deal with motion of entries due to rehashing. + // + private sealed class Container { - if (_freeList == -1) + private readonly ConditionalWeakTable<TKey, TValue> _parent; // the ConditionalWeakTable with which this container is associated + private int[] _buckets; // _buckets[hashcode & (_buckets.Length - 1)] contains index of the first entry in bucket (-1 if empty) + private Entry[] _entries; // the table entries containing the stored dependency handles + private int _firstFreeEntry; // _firstFreeEntry < _entries.Length => table has capacity, entries grow from the bottom of the table. + private bool _invalid; // flag detects if OOM or other background exception threw us out of the lock. + private bool _finalized; // set to true when initially finalized + private volatile object _oldKeepAlive; // used to ensure the next allocated container isn't finalized until this one is GC'd + + internal Container(ConditionalWeakTable<TKey, TValue> parent) { - Resize(); + Debug.Assert(parent != null); + Debug.Assert(IsPowerOfTwo(InitialCapacity)); + + int size = InitialCapacity; + _buckets = new int[size]; + for (int i = 0; i < _buckets.Length; i++) + { + _buckets[i] = -1; + } + _entries = new Entry[size]; + + // Only store the parent after all of the allocations have happened successfully. + // Otherwise, as part of growing or clearing the container, we could end up allocating + // a new Container that fails (OOMs) part way through construction but that gets finalized + // and ends up clearing out some other container present in the associated CWT. + _parent = parent; } - int hashCode = RuntimeHelpers.GetHashCode(key) & Int32.MaxValue; - int bucket = hashCode % _buckets.Length; + private Container(ConditionalWeakTable<TKey, TValue> parent, int[] buckets, Entry[] entries, int firstFreeEntry) + { + Debug.Assert(parent != null); + Debug.Assert(buckets != null); + Debug.Assert(entries != null); + Debug.Assert(buckets.Length == entries.Length); + Debug.Assert(IsPowerOfTwo(buckets.Length)); + + _parent = parent; + _buckets = buckets; + _entries = entries; + _firstFreeEntry = firstFreeEntry; + } - int newEntry = _freeList; - _freeList = _entries[newEntry].next; + internal bool HasCapacity => _firstFreeEntry < _entries.Length; - _entries[newEntry].hashCode = hashCode; - _entries[newEntry].depHnd = new DependentHandle(key, value); - _entries[newEntry].next = _buckets[bucket]; + //---------------------------------------------------------------------------------------- + // Worker for adding a new key/value pair. + // Preconditions: + // Container must NOT be full + //---------------------------------------------------------------------------------------- + internal void CreateEntryNoResize(TKey key, TValue value) + { + Debug.Assert(HasCapacity); - _buckets[bucket] = newEntry; + VerifyIntegrity(); + _invalid = true; - } + int hashCode = RuntimeHelpers.GetHashCode(key) & int.MaxValue; + int newEntry = _firstFreeEntry++; - //---------------------------------------------------------------------------------------- - // This does two things: resize and scrub expired keys off bucket lists. - // - // Precondition: - // Must hold _lock. - // - // Postcondition: - // _freeList is non-empty on exit. - //---------------------------------------------------------------------------------------- - [System.Security.SecurityCritical] - private void Resize() - { - // Start by assuming we won't resize. - int newSize = _buckets.Length; + _entries[newEntry].HashCode = hashCode; + _entries[newEntry].depHnd = new DependentHandle(key, value); + int bucket = hashCode & (_buckets.Length - 1); + _entries[newEntry].Next = _buckets[bucket]; + + // This write must be volatile, as we may be racing with concurrent readers. If they see + // the new entry, they must also see all of the writes earlier in this method. + Volatile.Write(ref _buckets[bucket], newEntry); + + _invalid = false; + } - // If any expired keys exist, we won't resize. - bool hasExpiredEntries = false; - int entriesIndex; - for (entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) + //---------------------------------------------------------------------------------------- + // Worker for finding a key/value pair + // + // Preconditions: + // Must hold _lock. + // Key already validated as non-null + //---------------------------------------------------------------------------------------- + internal bool TryGetValueWorker(TKey key, out TValue value) { - if ( _entries[entriesIndex].depHnd.IsAllocated && _entries[entriesIndex].depHnd.GetPrimary() == null) + object secondary; + int entryIndex = FindEntry(key, out secondary); + value = JitHelpers.UnsafeCast<TValue>(secondary); + return entryIndex != -1; + } + + //---------------------------------------------------------------------------------------- + // Returns -1 if not found (if key expires during FindEntry, this can be treated as "not found.") + // + // Preconditions: + // Must hold _lock, or be prepared to retry the search while holding _lock. + // Key already validated as non-null. + //---------------------------------------------------------------------------------------- + internal int FindEntry(TKey key, out object value) + { + int hashCode = RuntimeHelpers.GetHashCode(key) & int.MaxValue; + int bucket = hashCode & (_buckets.Length - 1); + for (int entriesIndex = Volatile.Read(ref _buckets[bucket]); entriesIndex != -1; entriesIndex = _entries[entriesIndex].Next) { - hasExpiredEntries = true; - break; + if (_entries[entriesIndex].HashCode == hashCode) + { + object primary, secondary; + _entries[entriesIndex].depHnd.GetPrimaryAndSecondary(out primary, out secondary); + if (primary == key) + { + GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. + value = secondary; + return entriesIndex; + } + } } + + GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. + value = null; + return -1; } - if (!hasExpiredEntries) + internal bool Remove(TKey key) { - newSize = System.Collections.HashHelpers.GetPrime(_buckets.Length == 0 ? _initialCapacity + 1 : _buckets.Length * 2); + VerifyIntegrity(); + + object value; + 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); + + return true; + } + + return false; } - // Reallocate both buckets and entries and rebuild the bucket and freelists from scratch. - // This serves both to scrub entries with expired keys and to put the new entries in the proper bucket. - int newFreeList = -1; - int[] newBuckets = new int[newSize]; - for (int bucketIndex = 0; bucketIndex < newSize; bucketIndex++) + internal void UpdateValue(int entryIndex, TValue newValue) { - newBuckets[bucketIndex] = -1; + Debug.Assert(entryIndex != -1); + + VerifyIntegrity(); + _invalid = true; + + _entries[entryIndex].depHnd.SetSecondary(newValue); + + _invalid = false; } - Entry[] newEntries = new Entry[newSize]; - // Migrate existing entries to the new table. - for (entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) + //---------------------------------------------------------------------------------------- + // This does two things: resize and scrub expired keys off bucket lists. + // + // Precondition: + // Must hold _lock. + // + // Postcondition: + // _firstEntry is less than _entries.Length on exit, that is, the table has at least one free entry. + //---------------------------------------------------------------------------------------- + internal Container Resize() { - DependentHandle depHnd = _entries[entriesIndex].depHnd; - if (depHnd.IsAllocated && depHnd.GetPrimary() != null) + // Start by assuming we won't resize. + int newSize = _buckets.Length; + + // If any expired or removed keys exist, we won't resize. + bool hasExpiredEntries = false; + for (int entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) { - // Entry is used and has not expired. Link it into the appropriate bucket list. - int bucket = _entries[entriesIndex].hashCode % newSize; - newEntries[entriesIndex].depHnd = depHnd; - newEntries[entriesIndex].hashCode = _entries[entriesIndex].hashCode; - newEntries[entriesIndex].next = newBuckets[bucket]; - newBuckets[bucket] = entriesIndex; + if (_entries[entriesIndex].HashCode == -1) + { + // the entry was removed + hasExpiredEntries = true; + break; + } + + if (_entries[entriesIndex].depHnd.IsAllocated && _entries[entriesIndex].depHnd.GetPrimary() == null) + { + // the entry has expired + hasExpiredEntries = true; + break; + } } - else + + if (!hasExpiredEntries) { - // Entry has either expired or was on the freelist to begin with. Either way - // insert it on the new freelist. - _entries[entriesIndex].depHnd.Free(); - newEntries[entriesIndex].depHnd = new DependentHandle(); - newEntries[entriesIndex].next = newFreeList; - newFreeList = entriesIndex; + // Not necessary to check for overflow here, the attempt to allocate new arrays will throw + newSize = _buckets.Length * 2; } + + return Resize(newSize); } - // Add remaining entries to freelist. - while (entriesIndex != newEntries.Length) + internal Container Resize(int newSize) { - newEntries[entriesIndex].depHnd = new DependentHandle(); - newEntries[entriesIndex].next = newFreeList; - newFreeList = entriesIndex; - entriesIndex++; - } + Debug.Assert(IsPowerOfTwo(newSize)); - _buckets = newBuckets; - _entries = newEntries; - _freeList = newFreeList; - } + // 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++) + { + newBuckets[bucketIndex] = -1; + } + Entry[] newEntries = new Entry[newSize]; + int newEntriesIndex = 0; - //---------------------------------------------------------------------------------------- - // Returns -1 if not found (if key expires during FindEntry, this can be treated as "not found.") - // - // Preconditions: - // Must hold _lock. - // Key already validated as non-null. - //---------------------------------------------------------------------------------------- - [System.Security.SecurityCritical] - private int FindEntry(TKey key) - { - int hashCode = RuntimeHelpers.GetHashCode(key) & Int32.MaxValue; - for (int entriesIndex = _buckets[hashCode % _buckets.Length]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].next) + // Migrate existing entries to the new table. + for (int entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++) + { + int hashCode = _entries[entriesIndex].HashCode; + DependentHandle depHnd = _entries[entriesIndex].depHnd; + if (hashCode != -1 && depHnd.IsAllocated) + { + 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 + { + // Pretend the item was removed, so that this container's finalizer + // will clean up this dependent handle. + Volatile.Write(ref _entries[entriesIndex].HashCode, -1); + } + } + } + + // Create the new container. We want to transfer the responsibility of freeing the handles from + // the old container to the new container, and also ensure that the new container isn't finalized + // 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); + _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. + + return newContainer; + } + + internal ICollection<TKey> Keys { - if (_entries[entriesIndex].hashCode == hashCode && _entries[entriesIndex].depHnd.GetPrimary() == key) + get { - return entriesIndex; + var list = new List<TKey>(); + + for (int bucket = 0; bucket < _buckets.Length; ++bucket) + { + for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].Next) + { + TKey thisKey = JitHelpers.UnsafeCast<TKey>(_entries[entriesIndex].depHnd.GetPrimary()); + if (thisKey != null) + { + list.Add(thisKey); + } + } + } + + GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. + return list; } } - return -1; - } - //---------------------------------------------------------------------------------------- - // Precondition: - // Must hold _lock. - //---------------------------------------------------------------------------------------- - private void VerifyIntegrity() - { - if (_invalid) + internal ICollection<TValue> Values { - throw new InvalidOperationException(Environment.GetResourceString("CollectionCorrupted")); + get + { + var list = new List<TValue>(); + + for (int bucket = 0; bucket < _buckets.Length; ++bucket) + { + for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].Next) + { + object primary = null, secondary = null; + _entries[entriesIndex].depHnd.GetPrimaryAndSecondary(out primary, out secondary); + + // Now that we've secured a strong reference to the secondary, must check the primary again + // to ensure it didn't expire (otherwise, we open a race where TryGetValue misreports an + // expired key as a live key with a null value.) + if (primary != null) + { + list.Add(JitHelpers.UnsafeCast<TValue>(secondary)); + } + } + } + + GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. + return list; + } } - } - //---------------------------------------------------------------------------------------- - // Finalizer. - //---------------------------------------------------------------------------------------- - [System.Security.SecuritySafeCritical] - ~ConditionalWeakTable() - { + internal TKey FindEquivalentKeyUnsafe(TKey key, out TValue value) + { + for (int bucket = 0; bucket < _buckets.Length; ++bucket) + { + for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].Next) + { + if (_entries[entriesIndex].HashCode == -1) + { + continue; // removed entry whose handle is awaiting condemnation by the finalizer. + } - // We're just freeing per-appdomain unmanaged handles here. If we're already shutting down the AD, - // don't bother. - // - // (Despite its name, Environment.HasShutdownStart also returns true if the current AD is finalizing.) - if (Environment.HasShutdownStarted) + object thisKey, thisValue; + _entries[entriesIndex].depHnd.GetPrimaryAndSecondary(out thisKey, out thisValue); + if (Equals(thisKey, key)) + { + GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. + value = JitHelpers.UnsafeCast<TValue>(thisValue); + return JitHelpers.UnsafeCast<TKey>(thisKey); + } + } + } + + GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles. + value = default(TValue); + return null; + } + + //---------------------------------------------------------------------------------------- + // Precondition: + // Must hold _lock. + //---------------------------------------------------------------------------------------- + private void VerifyIntegrity() { - return; + if (_invalid) + { + throw new InvalidOperationException(Environment.GetResourceString("CollectionCorrupted")); + } } - if (_lock != null) + //---------------------------------------------------------------------------------------- + // Finalizer. + //---------------------------------------------------------------------------------------- + ~Container() { - lock(_lock) + // We're just freeing per-appdomain unmanaged handles here. If we're already shutting down the AD, + // don't bother. (Despite its name, Environment.HasShutdownStart also returns true if the current + // AD is finalizing.) We also skip doing anything if the container is invalid, including if someone + // the container object was allocated but its associated table never set. + if (Environment.HasShutdownStarted || _invalid || _parent == null) { - if (_invalid) + return; + } + + // It's possible that the ConditionalWeakTable could have been resurrected, in which case code could + // be accessing this Container as it's being finalized. We don't support usage after finalization, + // but we also don't want to potentially corrupt state by allowing dependency handles to be used as + // or after they've been freed. To avoid that, if it's at all possible that another thread has a + // reference to this container via the CWT, we remove such a reference and then re-register for + // finalization: the next time around, we can be sure that no references remain to this and we can + // clean up the dependency handles without fear of corruption. + if (!_finalized) + { + _finalized = true; + lock (_parent._lock) { - return; + if (_parent._container == this) + { + _parent._container = null; + } } - Entry[] entries = _entries; + GC.ReRegisterForFinalize(this); // next time it's finalized, we'll be sure there are no remaining refs + return; + } - // Make sure anyone sneaking into the table post-resurrection - // gets booted before they can damage the native handle table. - _invalid = true; - _entries = null; - _buckets = null; + Entry[] entries = _entries; + _invalid = true; + _entries = null; + _buckets = null; + if (entries != null) + { for (int entriesIndex = 0; entriesIndex < entries.Length; entriesIndex++) { - entries[entriesIndex].depHnd.Free(); + // We need to free handles in two cases: + // - If this container still owns the dependency handle (meaning ownership hasn't been transferred + // to another container that replaced this one), then it should be freed. + // - If this container had the entry removed, then even if in general ownership was transferred to + // another container, removed entries are not, therefore this container must free them. + if (_oldKeepAlive == null || entries[entriesIndex].HashCode == -1) + { + entries[entriesIndex].depHnd.Free(); + } } } } } #endregion - - #region Private Data Members - //-------------------------------------------------------------------------------------------- - // Entry can be in one of three states: - // - // - Linked into the freeList (_freeList points to first entry) - // depHnd.IsAllocated == false - // hashCode == <dontcare> - // next links to next Entry on freelist) - // - // - Used with live key (linked into a bucket list where _buckets[hashCode % _buckets.Length] points to first entry) - // depHnd.IsAllocated == true, depHnd.GetPrimary() != null - // hashCode == RuntimeHelpers.GetHashCode(depHnd.GetPrimary()) & Int32.MaxValue - // next links to next Entry in bucket. - // - // - Used with dead key (linked into a bucket list where _buckets[hashCode % _buckets.Length] points to first entry) - // depHnd.IsAllocated == true, depHnd.GetPrimary() == null - // hashCode == <notcare> - // next links to next Entry in bucket. - // - // The only difference between "used with live key" and "used with dead key" is that - // depHnd.GetPrimary() returns null. The transition from "used with live key" to "used with dead key" - // happens asynchronously as a result of normal garbage collection. The dictionary itself - // receives no notification when this happens. - // - // When the dictionary grows the _entries table, it scours it for expired keys and puts those - // entries back on the freelist. - //-------------------------------------------------------------------------------------------- - private struct Entry - { - public DependentHandle depHnd; // Holds key and value using a weak reference for the key and a strong reference - // for the value that is traversed only if the key is reachable without going through the value. - public int hashCode; // Cached copy of key's hashcode - public int next; // Index of next entry, -1 if last - } - - private int[] _buckets; // _buckets[hashcode & _buckets.Length] contains index of first entry in bucket (-1 if empty) - private Entry[] _entries; - private int _freeList; // -1 = empty, else index of first unused Entry - private const int _initialCapacity = 5; - private readonly Object _lock; // this could be a ReaderWriterLock but CoreCLR does not support RWLocks. - private bool _invalid; // flag detects if OOM or other background exception threw us out of the lock. - #endregion } #endregion - - - #region DependentHandle //========================================================================================= // This struct collects all operations on native DependentHandles. The DependentHandle @@ -700,15 +816,10 @@ namespace System.Runtime.CompilerServices // to use DependentHandles in a thread-safe way. //========================================================================================= [ComVisible(false)] - struct DependentHandle + internal struct DependentHandle { #region Constructors - #if FEATURE_CORECLR - [System.Security.SecuritySafeCritical] // auto-generated - #else - [System.Security.SecurityCritical] - #endif - public DependentHandle(Object primary, Object secondary) + public DependentHandle(object primary, object secondary) { IntPtr handle = (IntPtr)0; nInitialize(primary, secondary, out handle); @@ -718,44 +829,37 @@ namespace System.Runtime.CompilerServices #endregion #region Public Members - public bool IsAllocated - { - get - { - return _handle != (IntPtr)0; - } - } + public bool IsAllocated => _handle != IntPtr.Zero; // Getting the secondary object is more expensive than getting the first so // we provide a separate primary-only accessor for those times we only want the // primary. - #if FEATURE_CORECLR - [System.Security.SecuritySafeCritical] // auto-generated - #else - [System.Security.SecurityCritical] - #endif - public Object GetPrimary() + public object GetPrimary() { - Object primary; + object primary; nGetPrimary(_handle, out primary); return primary; } - #if FEATURE_CORECLR - [System.Security.SecuritySafeCritical] // auto-generated - #else - [System.Security.SecurityCritical] - #endif - public void GetPrimaryAndSecondary(out Object primary, out Object secondary) + public void GetPrimaryAndSecondary(out object primary, out object secondary) { nGetPrimaryAndSecondary(_handle, out primary, out secondary); } + public void SetPrimary(object primary) + { + nSetPrimary(_handle, primary); + } + + public void SetSecondary(object secondary) + { + nSetSecondary(_handle, secondary); + } + //---------------------------------------------------------------------- // Forces dependentHandle back to non-allocated state (if not already there) // and frees the handle if needed. //---------------------------------------------------------------------- - [System.Security.SecurityCritical] public void Free() { if (_handle != (IntPtr)0) @@ -768,20 +872,22 @@ namespace System.Runtime.CompilerServices #endregion #region Private Members - [System.Security.SecurityCritical] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern void nInitialize(Object primary, Object secondary, out IntPtr dependentHandle); + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void nInitialize(object primary, object secondary, out IntPtr dependentHandle); + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void nGetPrimary(IntPtr dependentHandle, out object primary); - [System.Security.SecurityCritical] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern void nGetPrimary(IntPtr dependentHandle, out Object primary); + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void nGetPrimaryAndSecondary(IntPtr dependentHandle, out object primary, out object secondary); - [System.Security.SecurityCritical] - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern void nGetPrimaryAndSecondary(IntPtr dependentHandle, out Object primary, out Object secondary); + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void nSetPrimary(IntPtr dependentHandle, object primary); - [System.Security.SecurityCritical] - [MethodImplAttribute(MethodImplOptions.InternalCall)] + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void nSetSecondary(IntPtr dependentHandle, object secondary); + + [MethodImpl(MethodImplOptions.InternalCall)] private static extern void nFree(IntPtr dependentHandle); #endregion @@ -792,4 +898,3 @@ namespace System.Runtime.CompilerServices } // struct DependentHandle #endregion } - diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs index 39a4c86b72..7bfaa7aafd 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs @@ -6,6 +6,7 @@ // Note: If you add a new ctor overloads you need to update ParameterInfo.RawDefaultValue using System.Reflection; +using System.Diagnostics; using System.Diagnostics.Contracts; using System.Collections.Generic; @@ -57,16 +58,16 @@ namespace System.Runtime.CompilerServices if (namedArgument.MemberInfo.Name.Equals("Value")) { // This is not possible because Decimal cannot be represented directly in the metadata. - Contract.Assert(false, "Decimal cannot be represented directly in the metadata."); + Debug.Assert(false, "Decimal cannot be represented directly in the metadata."); return (Decimal)namedArgument.TypedValue.Value; } } ParameterInfo[] parameters = attr.Constructor.GetParameters(); - Contract.Assert(parameters.Length == 5); + Debug.Assert(parameters.Length == 5); System.Collections.Generic.IList<CustomAttributeTypedArgument> args = attr.ConstructorArguments; - Contract.Assert(args.Count == 5); + Debug.Assert(args.Count == 5); if (parameters[2].ParameterType == typeof(uint)) { diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/FormattableStringFactory.cs b/src/mscorlib/src/System/Runtime/CompilerServices/FormattableStringFactory.cs index aee3bc2230..4b99a8a5d9 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/FormattableStringFactory.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/FormattableStringFactory.cs @@ -26,12 +26,12 @@ namespace System.Runtime.CompilerServices { if (format == null) { - throw new ArgumentNullException("format"); + throw new ArgumentNullException(nameof(format)); } if (arguments == null) { - throw new ArgumentNullException("arguments"); + throw new ArgumentNullException(nameof(arguments)); } return new ConcreteFormattableString(format, arguments); diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/HasCopySemanticsAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/HasCopySemanticsAttribute.cs deleted file mode 100644 index 944a2868f2..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/HasCopySemanticsAttribute.cs +++ /dev/null @@ -1,14 +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 -{ -[Serializable] -[AttributeUsage(AttributeTargets.Struct)] - public sealed class HasCopySemanticsAttribute : Attribute - { - public HasCopySemanticsAttribute() - {} - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IDispatchConstantAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IDispatchConstantAttribute.cs deleted file mode 100644 index d6dfcbbbb9..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IDispatchConstantAttribute.cs +++ /dev/null @@ -1,26 +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.Runtime.InteropServices; - -namespace System.Runtime.CompilerServices -{ -[Serializable] -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter, Inherited=false)] -[System.Runtime.InteropServices.ComVisible(true)] - public sealed class IDispatchConstantAttribute : CustomConstantAttribute - { - public IDispatchConstantAttribute() - { - } - - public override Object Value - { - get - { - return new DispatchWrapper(null); - } - } - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/INotifyCompletion.cs b/src/mscorlib/src/System/Runtime/CompilerServices/INotifyCompletion.cs index 872a79b72b..aba0a0691f 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/INotifyCompletion.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/INotifyCompletion.cs @@ -34,7 +34,6 @@ namespace System.Runtime.CompilerServices /// <param name="continuation">The action to invoke when the operation completes.</param> /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> /// <remarks>Unlike OnCompleted, UnsafeOnCompleted need not propagate ExecutionContext information.</remarks> - [SecurityCritical] void UnsafeOnCompleted(Action continuation); } } diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IUnknownConstantAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IUnknownConstantAttribute.cs deleted file mode 100644 index f8717cff52..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IUnknownConstantAttribute.cs +++ /dev/null @@ -1,27 +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.Runtime.InteropServices; - -namespace System.Runtime.CompilerServices -{ -[Serializable] -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter, Inherited=false)] -[System.Runtime.InteropServices.ComVisible(true)] - public sealed class IUnknownConstantAttribute : CustomConstantAttribute - { - public IUnknownConstantAttribute() - { - } - - public override Object Value - { - get - { - return new UnknownWrapper(null); - } - } - - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsBoxed.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsBoxed.cs deleted file mode 100644 index 8b6691c09d..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsBoxed.cs +++ /dev/null @@ -1,11 +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 -{ - // Indicates that the modified reference type is a boxed valuetype - public static class IsBoxed - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsByValue.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsByValue.cs deleted file mode 100644 index d16a853597..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsByValue.cs +++ /dev/null @@ -1,11 +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 -{ - // Indicates that the modified method argument is passed by value - public static class IsByValue - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsConst.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsConst.cs deleted file mode 100644 index 210e5997a7..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsConst.cs +++ /dev/null @@ -1,11 +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 -{ - // Indicates that the modified type is const (i.e. has a const modifier) - public static class IsConst - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsCopyConstructed.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsCopyConstructed.cs deleted file mode 100644 index ee40ee7b02..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsCopyConstructed.cs +++ /dev/null @@ -1,11 +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 -{ - [System.Runtime.InteropServices.ComVisible(true)] - public static class IsCopyConstructed - {} -} - diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsExplicitlyDereferenced.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsExplicitlyDereferenced.cs deleted file mode 100644 index 480a62175d..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsExplicitlyDereferenced.cs +++ /dev/null @@ -1,22 +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 -{ - // Consider the following C++ method prototypes: - // 1) int foo(int ^arg); - // 2) int foo(int &arg); - // - // Both of these methods will have a .NET type signature that looks the - // same, but when importing a method from a metadata scope, the compiler - // needs to know what the calling syntax should be. This modopt and its - // partner "IsImplicitlyDereferenced" disambiguate reference versus - // pointer arguments. - // - // Indicates that the modified GC reference represents a pointer in a - // method signature. - public static class IsExplicitlyDereferenced - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsImplicitlyDereferenced.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsImplicitlyDereferenced.cs deleted file mode 100644 index ea81cb8ec5..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsImplicitlyDereferenced.cs +++ /dev/null @@ -1,22 +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 -{ - // Consider the following C++ method prototypes: - // 1) int foo(int ^arg); - // 2) int foo(int &arg); - // - // Both of these methods will have a .NET type signature that looks the - // same, but when importing a method from a metadata scope, the compiler - // needs to know what the calling syntax should be. This modopt and its - // partner "IsExplicitlyDereferenced" disambiguate reference versus - // pointer arguments. - // - // Indicates that the modified GC reference represents a reference in a - // method signature. - public static class IsImplicitlyDereferenced - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsJitIntrinsic.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsJitIntrinsic.cs deleted file mode 100644 index 013e50f3ea..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsJitIntrinsic.cs +++ /dev/null @@ -1,12 +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 -{ - // Indicates that the modified method is an intrinsic for which the JIT - // can perform special code generation. - public static class IsJitIntrinsic - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsLong.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsLong.cs deleted file mode 100644 index e8bebfb2d3..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsLong.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. - -namespace System.Runtime.CompilerServices -{ - // The C++ standard indicates that a long is always 4-bytes, whereas the - // size of an integer is system dependent (not exceedign sizeof(long)). - // The CLR does not offer a mechanism for encoding this distinction, - // but it is critically important for maintaining language level type - // safety. - // - // Indicates that the modified integer is a standard C++ long. - // Could also be called IsAlternateIntegerType or something else. - public static class IsLong - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsPinned.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsPinned.cs deleted file mode 100644 index e796d1a1e7..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsPinned.cs +++ /dev/null @@ -1,11 +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 -{ - // Indicates that the modified instance is pinned in memory. - public static class IsPinned - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsSignUnspecifiedByte.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsSignUnspecifiedByte.cs deleted file mode 100644 index e68f4d7751..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsSignUnspecifiedByte.cs +++ /dev/null @@ -1,16 +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 -{ - // C++ recognizes three char types: signed char, unsigned char, and char. - // When a char is neither signed nor unsigned, it is a char. - // This modopt indicates that the modified instance is a char. - // - // Any compiler could use this to indicate that the user has not specified - // Sign behavior for the given byte. - public static class IsSignUnspecifiedByte - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/IsUdtReturn.cs b/src/mscorlib/src/System/Runtime/CompilerServices/IsUdtReturn.cs deleted file mode 100644 index dd85914b53..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/IsUdtReturn.cs +++ /dev/null @@ -1,11 +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 -{ - // Indicates that the return type is a user defined type - public static class IsUdtReturn - { - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/NativeCppClassAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/NativeCppClassAttribute.cs deleted file mode 100644 index 0d6c759d76..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/NativeCppClassAttribute.cs +++ /dev/null @@ -1,16 +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 { -[Serializable] -[AttributeUsage(AttributeTargets.Struct, Inherited = true), - System.Runtime.InteropServices.ComVisible(true)] - public sealed class NativeCppClassAttribute : Attribute - { - public NativeCppClassAttribute () {} - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/RequiredAttributeAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/RequiredAttributeAttribute.cs deleted file mode 100644 index f363696ebd..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/RequiredAttributeAttribute.cs +++ /dev/null @@ -1,26 +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; - -namespace System.Runtime.CompilerServices -{ -[Serializable] -[AttributeUsage (AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface, - AllowMultiple=true, Inherited=false)] -[System.Runtime.InteropServices.ComVisible(true)] - public sealed class RequiredAttributeAttribute : Attribute - { - private Type requiredContract; - - public RequiredAttributeAttribute (Type requiredContract) - { - this.requiredContract= requiredContract; - } - public Type RequiredContract - { - get { return this.requiredContract; } - } - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index d20fe0bffd..926eb6c3cb 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -25,16 +25,13 @@ namespace System.Runtime.CompilerServices { public static class RuntimeHelpers { -#if FEATURE_CORECLR // Exposed here as a more appropriate place than on FormatterServices itself, // which is a high level reflection heavy type. public static Object GetUninitializedObject(Type type) { return FormatterServices.GetUninitializedObject(type); } -#endif // FEATURE_CORECLR - [System.Security.SecuritySafeCritical] // auto-generated [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern void InitializeArray(Array array,RuntimeFieldHandle fldHandle); @@ -51,7 +48,6 @@ namespace System.Runtime.CompilerServices { // cloned when you pass them around, and are always passed by value. // Of course, reference types are not cloned. // - [System.Security.SecuritySafeCritical] // auto-generated [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern Object GetObjectValue(Object obj); @@ -63,7 +59,6 @@ namespace System.Runtime.CompilerServices { // This call will generate an exception if the specified class constructor threw an // exception when it ran. - [System.Security.SecuritySafeCritical] [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern void _RunClassConstructor(RuntimeType type); @@ -80,7 +75,6 @@ namespace System.Runtime.CompilerServices { // This call will generate an exception if the specified module constructor threw an // exception when it ran. - [System.Security.SecuritySafeCritical] [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern void _RunModuleConstructor(System.Reflection.RuntimeModule module); @@ -89,72 +83,25 @@ namespace System.Runtime.CompilerServices { _RunModuleConstructor(module.GetRuntimeModule()); } - [System.Security.SecurityCritical] // auto-generated - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static unsafe extern void _PrepareMethod(IRuntimeMethodInfo method, IntPtr* pInstantiation, int cInstantiation); - [System.Security.SecurityCritical] // auto-generated [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] internal static extern void _CompileMethod(IRuntimeMethodInfo method); - // Simple (instantiation not required) method. - [System.Security.SecurityCritical] // auto-generated_required - public static void PrepareMethod(RuntimeMethodHandle method) + public static void PrepareMethod(RuntimeMethodHandle method){} + public static void PrepareMethod(RuntimeMethodHandle method, RuntimeTypeHandle[] instantiation){} + public static void PrepareContractedDelegate(Delegate d){} + + public static void PrepareDelegate(Delegate d) { - unsafe + if (d == null) { - _PrepareMethod(method.GetMethodInfo(), null, 0); + throw new ArgumentNullException ("d"); } } - // Generic method or method with generic class with specific instantiation. - [System.Security.SecurityCritical] // auto-generated_required - public static void PrepareMethod(RuntimeMethodHandle method, RuntimeTypeHandle[] instantiation) - { - unsafe - { - int length; - IntPtr[] instantiationHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(instantiation, out length); - fixed (IntPtr* pInstantiation = instantiationHandles) - { - _PrepareMethod(method.GetMethodInfo(), pInstantiation, length); - GC.KeepAlive(instantiation); - } - } - } - - // This method triggers a given delegate to be prepared. This involves preparing the - // delegate's Invoke method and preparing the target of that Invoke. In the case of - // a multi-cast delegate, we rely on the fact that each individual component was prepared - // prior to the Combine. In other words, this service does not navigate through the - // entire multicasting list. - // If our own reliable event sinks perform the Combine (for example AppDomain.DomainUnload), - // then the result is fully prepared. But if a client calls Combine himself and then - // then adds that combination to e.g. AppDomain.DomainUnload, then the client is responsible - // for his own preparation. - [System.Security.SecurityCritical] // auto-generated_required - [MethodImplAttribute(MethodImplOptions.InternalCall)] - public static extern void PrepareDelegate(Delegate d); - - // See comment above for PrepareDelegate - // - // PrepareContractedDelegate weakens this a bit by only assuring that we prepare - // delegates which also have a ReliabilityContract. This is useful for services that - // want to provide opt-in reliability, generally some random event sink providing - // always reliable semantics to random event handlers that are likely to have not - // been written with relability in mind is a lost cause anyway. - // - // NOTE: that for the NGen case you can sidestep the required ReliabilityContract - // by using the [PrePrepareMethod] attribute. - [System.Security.SecurityCritical] // auto-generated_required - [MethodImplAttribute(MethodImplOptions.InternalCall)] - public static extern void PrepareContractedDelegate(Delegate d); - - [System.Security.SecuritySafeCritical] // auto-generated [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern int GetHashCode(Object o); - [System.Security.SecuritySafeCritical] // auto-generated [MethodImplAttribute(MethodImplOptions.InternalCall)] public new static extern bool Equals(Object o1, Object o2); @@ -183,30 +130,24 @@ namespace System.Runtime.CompilerServices { // If there is not enough stack, then it throws System.InsufficientExecutionStackException. // Note: this method is not part of the CER support, and is not to be confused with ProbeForSufficientStack // below. - [System.Security.SecuritySafeCritical] [MethodImplAttribute(MethodImplOptions.InternalCall)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static extern void EnsureSufficientExecutionStack(); -#if FEATURE_CORECLR // This method ensures that there is sufficient stack to execute the average Framework function. // If there is not enough stack, then it return false. // Note: this method is not part of the CER support, and is not to be confused with ProbeForSufficientStack // below. - [System.Security.SecuritySafeCritical] [MethodImplAttribute(MethodImplOptions.InternalCall)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - internal static extern bool TryEnsureSufficientExecutionStack(); -#endif + public static extern bool TryEnsureSufficientExecutionStack(); - [System.Security.SecurityCritical] // auto-generated_required - [MethodImplAttribute(MethodImplOptions.InternalCall)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - public static extern void ProbeForSufficientStack(); + public static void ProbeForSufficientStack() + { + } // 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. - [System.Security.SecurityCritical] // auto-generated_required [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void PrepareConstrainedRegions() { @@ -215,29 +156,18 @@ 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. - [System.Security.SecurityCritical] // auto-generated_required [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void PrepareConstrainedRegionsNoOP() { } - #if FEATURE_CORECLR - [System.Security.SecurityCritical] // auto-generated - #endif public delegate void TryCode(Object userData); - #if FEATURE_CORECLR - [System.Security.SecurityCritical] // auto-generated - #endif public delegate void CleanupCode(Object userData, bool exceptionThrown); - [System.Security.SecurityCritical] // auto-generated_required [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern void ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData); -#if FEATURE_CORECLR - [System.Security.SecurityCritical] // auto-generated -#endif [PrePrepareMethod] internal static void ExecuteBackoutCodeHelper(Object backoutCode, Object userData, bool exceptionThrown) { diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs index 2751d61db7..d2691df6b9 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs @@ -33,10 +33,9 @@ namespace System.Runtime.CompilerServices { private Object m_wrappedException; - [System.Security.SecurityCritical] // auto-generated_required public override void GetObjectData(SerializationInfo info, StreamingContext context) { if (info==null) { - throw new ArgumentNullException("info"); + throw new ArgumentNullException(nameof(info)); } Contract.EndContractBlock(); base.GetObjectData(info, context); diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/ScopelessEnumAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/ScopelessEnumAttribute.cs deleted file mode 100644 index 91769187cc..0000000000 --- a/src/mscorlib/src/System/Runtime/CompilerServices/ScopelessEnumAttribute.cs +++ /dev/null @@ -1,14 +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 -{ -[Serializable] -[AttributeUsage(AttributeTargets.Enum)] - public sealed class ScopelessEnumAttribute : Attribute - { - public ScopelessEnumAttribute() - {} - } -} diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs index ea6bb96e16..98a81ea470 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs @@ -57,7 +57,6 @@ namespace System.Runtime.CompilerServices { /// <summary>Provides an awaiter for awaiting a <see cref="System.Threading.Tasks.Task"/>.</summary> /// <remarks>This type is intended for compiler use only.</remarks> - [HostProtection(Synchronization = true, ExternalThreading = true)] public struct TaskAwaiter : ICriticalNotifyCompletion { /// <summary>The task being awaited.</summary> @@ -84,7 +83,6 @@ namespace System.Runtime.CompilerServices /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> /// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception> /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - [SecuritySafeCritical] public void OnCompleted(Action continuation) { OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:true); @@ -95,7 +93,6 @@ namespace System.Runtime.CompilerServices /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> /// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception> /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks> - [SecurityCritical] public void UnsafeOnCompleted(Action continuation) { OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:false); @@ -143,7 +140,7 @@ namespace System.Runtime.CompilerServices if (!task.IsCompleted) { bool taskCompleted = task.InternalWait(Timeout.Infinite, default(CancellationToken)); - Contract.Assert(taskCompleted, "With an infinite timeout, the task should have always completed."); + Debug.Assert(taskCompleted, "With an infinite timeout, the task should have always completed."); } // Now that we're done, alert the debugger if so requested @@ -171,7 +168,7 @@ namespace System.Runtime.CompilerServices if (oceEdi != null) { oceEdi.Throw(); - Contract.Assert(false, "Throw() should have thrown"); + Debug.Assert(false, "Throw() should have thrown"); } throw new TaskCanceledException(task); @@ -182,12 +179,12 @@ namespace System.Runtime.CompilerServices if (edis.Count > 0) { edis[0].Throw(); - Contract.Assert(false, "Throw() should have thrown"); + Debug.Assert(false, "Throw() should have thrown"); break; // Necessary to compile: non-reachable, but compiler can't determine that } else { - Contract.Assert(false, "There should be exceptions if we're Faulted."); + Debug.Assert(false, "There should be exceptions if we're Faulted."); throw task.Exception; } } @@ -202,10 +199,9 @@ namespace System.Runtime.CompilerServices /// <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 - [SecurityCritical] internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, bool flowExecutionContext) { - if (continuation == null) throw new ArgumentNullException("continuation"); + 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 @@ -294,7 +290,6 @@ namespace System.Runtime.CompilerServices /// <summary>Provides an awaiter for awaiting a <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary> /// <remarks>This type is intended for compiler use only.</remarks> - [HostProtection(Synchronization = true, ExternalThreading = true)] public struct TaskAwaiter<TResult> : ICriticalNotifyCompletion { /// <summary>The task being awaited.</summary> @@ -321,7 +316,6 @@ 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> - [SecuritySafeCritical] public void OnCompleted(Action continuation) { TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:true); @@ -332,7 +326,6 @@ 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> - [SecurityCritical] public void UnsafeOnCompleted(Action continuation) { TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:false); @@ -377,7 +370,6 @@ namespace System.Runtime.CompilerServices /// <summary>Provides an awaiter for a <see cref="ConfiguredTaskAwaitable"/>.</summary> /// <remarks>This type is intended for compiler use only.</remarks> - [HostProtection(Synchronization = true, ExternalThreading = true)] public struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion { /// <summary>The task being awaited.</summary> @@ -411,7 +403,6 @@ 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> - [SecuritySafeCritical] public void OnCompleted(Action continuation) { TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:true); @@ -422,7 +413,6 @@ 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> - [SecurityCritical] public void UnsafeOnCompleted(Action continuation) { TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:false); @@ -466,7 +456,6 @@ namespace System.Runtime.CompilerServices /// <summary>Provides an awaiter for a <see cref="ConfiguredTaskAwaitable{TResult}"/>.</summary> /// <remarks>This type is intended for compiler use only.</remarks> - [HostProtection(Synchronization = true, ExternalThreading = true)] public struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion { /// <summary>The task being awaited.</summary> @@ -499,7 +488,6 @@ 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> - [SecuritySafeCritical] public void OnCompleted(Action continuation) { TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:true); @@ -510,7 +498,6 @@ 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> - [SecurityCritical] public void UnsafeOnCompleted(Action continuation) { TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:false); diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TypeDependencyAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TypeDependencyAttribute.cs index db04eb9348..2de9c1f785 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/TypeDependencyAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/TypeDependencyAttribute.cs @@ -17,7 +17,7 @@ namespace System.Runtime.CompilerServices public TypeDependencyAttribute (string typeName) { - if(typeName == null) throw new ArgumentNullException("typeName"); + if(typeName == null) throw new ArgumentNullException(nameof(typeName)); Contract.EndContractBlock(); this.typeName = typeName; } diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs index c1656dcf99..671d1f0071 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs @@ -20,7 +20,7 @@ namespace System.Runtime.CompilerServices { if (String.IsNullOrEmpty(assemblyFullName)) { - throw new ArgumentNullException("assemblyFullName"); + throw new ArgumentNullException(nameof(assemblyFullName)); } this.assemblyFullName = assemblyFullName; } diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs index 034dad1afe..d9e067bd4c 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs @@ -26,7 +26,6 @@ namespace System.Runtime.CompilerServices } } - [System.Security.SecurityCritical] internal static TypeForwardedToAttribute[] GetCustomAttribute(RuntimeAssembly assembly) { Type[] types = null; diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs new file mode 100644 index 0000000000..b212f4555b --- /dev/null +++ b/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -0,0 +1,80 @@ +// 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.Runtime.Versioning; + +namespace System.Runtime.CompilerServices +{ + // + // Subsetted clone of System.Runtime.CompilerServices.Unsafe for internal runtime use. + // Keep in sync with https://github.com/dotnet/corefx/tree/master/src/System.Runtime.CompilerServices.Unsafe. + // + + /// <summary> + /// Contains generic, low-level functionality for manipulating pointers. + /// </summary> + internal static unsafe class Unsafe + { + /// <summary> + /// Returns a pointer to the given by-ref parameter. + /// </summary> + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void* AsPointer<T>(ref T value) + { + // The body of this function will be replaced by the EE with unsafe code!!! + // See getILIntrinsicImplementationForUnsafe for how this happens. + throw new InvalidOperationException(); + } + + /// <summary> + /// Returns the size of an object of the given type parameter. + /// </summary> + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SizeOf<T>() + { + // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T + // See getILIntrinsicImplementationForUnsafe for how this happens. + throw new InvalidOperationException(); + } + + /// <summary> + /// Reinterprets the given reference as a reference to a value of type <typeparamref name="TTo"/>. + /// </summary> + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref TTo As<TFrom, TTo>(ref TFrom source) + { + // The body of this function will be replaced by the EE with unsafe code!!! + // See getILIntrinsicImplementationForUnsafe for how this happens. + throw new InvalidOperationException(); + } + + /// <summary> + /// Adds an element offset to the given reference. + /// </summary> + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref T Add<T>(ref T source, int elementOffset) + { + // The body of this function will be replaced by the EE with unsafe code!!! + // See getILIntrinsicImplementationForUnsafe for how this happens. + typeof(T).ToString(); // Type used by the actual method body + throw new InvalidOperationException(); + } + + /// <summary> + /// Determines whether the specified references point to the same location. + /// </summary> + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool AreSame<T>(ref T left, ref T right) + { + // 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 b29b39c5bf..86789bf12d 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/YieldAwaitable.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/YieldAwaitable.cs @@ -48,7 +48,6 @@ namespace System.Runtime.CompilerServices /// <summary>Provides an awaiter that switches into a target environment.</summary> /// <remarks>This type is intended for compiler use only.</remarks> - [HostProtection(Synchronization = true, ExternalThreading = true)] public struct YieldAwaiter : ICriticalNotifyCompletion { /// <summary>Gets whether a yield is not required.</summary> @@ -58,7 +57,6 @@ namespace System.Runtime.CompilerServices /// <summary>Posts the <paramref name="continuation"/> back to the current context.</summary> /// <param name="continuation">The action to invoke asynchronously.</param> /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - [SecuritySafeCritical] public void OnCompleted(Action continuation) { QueueContinuation(continuation, flowContext: true); @@ -67,7 +65,6 @@ namespace System.Runtime.CompilerServices /// <summary>Posts the <paramref name="continuation"/> back to the current context.</summary> /// <param name="continuation">The action to invoke asynchronously.</param> /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - [SecurityCritical] public void UnsafeOnCompleted(Action continuation) { QueueContinuation(continuation, flowContext: false); @@ -77,11 +74,10 @@ namespace System.Runtime.CompilerServices /// <param name="continuation">The action to invoke asynchronously.</param> /// <param name="flowContext">true to flow ExecutionContext; false if flowing is not required.</param> /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception> - [SecurityCritical] private static void QueueContinuation(Action continuation, bool flowContext) { // Validate arguments - if (continuation == null) throw new ArgumentNullException("continuation"); + if (continuation == null) throw new ArgumentNullException(nameof(continuation)); Contract.EndContractBlock(); if (TplEtwProvider.Log.IsEnabled()) diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs index 8ee50da290..c1346f7527 100644 --- a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs +++ b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs @@ -11,6 +11,7 @@ using System; using System.Threading; using System.Runtime; using System.Runtime.Versioning; +using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime.InteropServices; using System.Security; @@ -60,6 +61,12 @@ namespace System.Runtime.CompilerServices { public byte m_data; } + internal class ArrayPinningHelper + { + public IntPtr m_lengthAndPadding; + public byte m_arrayData; + } + [FriendAccessAllowed] internal static class JitHelpers { @@ -68,7 +75,6 @@ namespace System.Runtime.CompilerServices { // Wraps object variable into a handle. Used to return managed strings from QCalls. // s has to be a local variable on the stack. - [SecurityCritical] static internal StringHandleOnStack GetStringHandleOnStack(ref string s) { return new StringHandleOnStack(UnsafeCastToStackPointer(ref s)); @@ -76,7 +82,6 @@ namespace System.Runtime.CompilerServices { // Wraps object variable into a handle. Used to pass managed object references in and out of QCalls. // o has to be a local variable on the stack. - [SecurityCritical] static internal ObjectHandleOnStack GetObjectHandleOnStack<T>(ref T o) where T : class { return new ObjectHandleOnStack(UnsafeCastToStackPointer(ref o)); @@ -84,25 +89,22 @@ namespace System.Runtime.CompilerServices { // Wraps StackCrawlMark into a handle. Used to pass StackCrawlMark to QCalls. // stackMark has to be a local variable on the stack. - [SecurityCritical] static internal StackCrawlMarkHandle GetStackCrawlMarkHandle(ref StackCrawlMark stackMark) { return new StackCrawlMarkHandle(UnsafeCastToStackPointer(ref stackMark)); } #if _DEBUG - [SecurityCritical] [FriendAccessAllowed] static internal T UnsafeCast<T>(Object o) where T : class { T ret = UnsafeCastInternal<T>(o); - Contract.Assert(ret == (o as T), "Invalid use of JitHelpers.UnsafeCast!"); + Debug.Assert(ret == (o as T), "Invalid use of JitHelpers.UnsafeCast!"); return ret; } // The IL body of this method is not critical, but its body will be replaced with unsafe code, so // this method is effectively critical - [SecurityCritical] static private T UnsafeCastInternal<T>(Object o) where T : class { // The body of this function will be replaced by the EE with unsafe code that just returns o!!! @@ -112,7 +114,7 @@ namespace System.Runtime.CompilerServices { static internal int UnsafeEnumCast<T>(T val) where T : struct // Actually T must be 4 byte (or less) enum { - Contract.Assert(typeof(T).IsEnum + Debug.Assert(typeof(T).IsEnum && (Enum.GetUnderlyingType(typeof(T)) == typeof(int) || Enum.GetUnderlyingType(typeof(T)) == typeof(uint) || Enum.GetUnderlyingType(typeof(T)) == typeof(short) @@ -132,7 +134,7 @@ namespace System.Runtime.CompilerServices { static internal long UnsafeEnumCastLong<T>(T val) where T : struct // Actually T must be 8 byte enum { - Contract.Assert(typeof(T).IsEnum + Debug.Assert(typeof(T).IsEnum && (Enum.GetUnderlyingType(typeof(T)) == typeof(long) || Enum.GetUnderlyingType(typeof(T)) == typeof(ulong)), "Error, T must be an 8 byte enum JitHelpers.UnsafeEnumCastLong!"); @@ -148,15 +150,13 @@ namespace System.Runtime.CompilerServices { // Internal method for getting a raw pointer for handles in JitHelpers. // The reference has to point into a local stack variable in order so it can not be moved by the GC. - [SecurityCritical] static internal IntPtr UnsafeCastToStackPointer<T>(ref T val) { IntPtr p = UnsafeCastToStackPointerInternal<T>(ref val); - Contract.Assert(IsAddressInStack(p), "Pointer not in the stack!"); + Debug.Assert(IsAddressInStack(p), "Pointer not in the stack!"); return p; } - [SecurityCritical] static private IntPtr UnsafeCastToStackPointerInternal<T>(ref T val) { // The body of this function will be replaced by the EE with unsafe code that just returns val!!! @@ -166,7 +166,6 @@ namespace System.Runtime.CompilerServices { #else // _DEBUG // The IL body of this method is not critical, but its body will be replaced with unsafe code, so // this method is effectively critical - [SecurityCritical] [FriendAccessAllowed] static internal T UnsafeCast<T>(Object o) where T : class { @@ -189,7 +188,6 @@ namespace System.Runtime.CompilerServices { throw new InvalidOperationException(); } - [SecurityCritical] static internal IntPtr UnsafeCastToStackPointer<T>(ref T val) { // The body of this function will be replaced by the EE with unsafe code that just returns o!!! @@ -199,12 +197,10 @@ namespace System.Runtime.CompilerServices { #endif // _DEBUG // Set the given element in the array without any type or range checks - [SecurityCritical] [MethodImplAttribute(MethodImplOptions.InternalCall)] extern static internal void UnsafeSetArrayElement(Object[] target, int index, Object element); // Used for unsafe pinning of arbitrary objects. - [System.Security.SecurityCritical] // auto-generated static internal PinningHelper GetPinningHelper(Object o) { // This cast is really unsafe - call the private version that does not assert in debug @@ -216,9 +212,33 @@ namespace System.Runtime.CompilerServices { } #if _DEBUG - [SecurityCritical] [MethodImplAttribute(MethodImplOptions.InternalCall)] 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!!! + // See getILIntrinsicImplementation for how this happens. + throw new InvalidOperationException(); + } + + /// <returns>true if given type is reference type or value type that contains references</returns> + static internal bool ContainsReferences<T>() + { + // 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>(T[] array) + { + // The body of this function will be replaced by the EE with unsafe code!!! + // See getILIntrinsicImplementation for how this happens. + typeof(ArrayPinningHelper).ToString(); // Type used by the actual method body + throw new InvalidOperationException(); + } +#endif // FEATURE_SPAN_OF_T } } |