summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Runtime/CompilerServices
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Runtime/CompilerServices')
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs58
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/CallingConvention.cs30
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs905
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/DecimalConstantAttribute.cs7
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/FormattableStringFactory.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/HasCopySemanticsAttribute.cs14
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IDispatchConstantAttribute.cs26
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/INotifyCompletion.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IUnknownConstantAttribute.cs27
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsBoxed.cs11
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsByValue.cs11
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsConst.cs11
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsCopyConstructed.cs11
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsExplicitlyDereferenced.cs22
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsImplicitlyDereferenced.cs22
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsJitIntrinsic.cs12
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsLong.cs18
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsPinned.cs11
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsSignUnspecifiedByte.cs16
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/IsUdtReturn.cs11
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/NativeCppClassAttribute.cs16
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/RequiredAttributeAttribute.cs26
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs92
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/RuntimeWrappedException.cs3
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/ScopelessEnumAttribute.cs14
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs23
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/TypeDependencyAttribute.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/TypeForwardedToAttribute.cs1
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs80
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/YieldAwaitable.cs6
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs52
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
}
}