Address PR feedback and other cleanup
authorStephen Toub <stoub@microsoft.com>
Sun, 5 Feb 2017 14:27:53 +0000 (09:27 -0500)
committerStephen Toub <stoub@microsoft.com>
Sun, 5 Feb 2017 14:47:44 +0000 (09:47 -0500)
Addressed PR comment about removing ExecutionContext.Capture(ref StackCrawlMark, ...), which led me to remove NoInlining/StackCrawlMarks from some other places in Timer, Thread, ThreadPool, and Overlapped.

In doing so, I found several other unnecessary members on ExecutionContext that could be removed with minor tweaks elsewhere in the source, e.g.
- Dispose is a nop, so we can remove explicit try/finally's to clean it up
- ExecutionContext.Run(..., bool) just ignores the bool arg, so it can be removed and all call sites redirected (but I've left it in EC, as it appears it's used via internals visible from a library in corefx)
- FastCapture() just calls Capture, so the call sites can be changed (but I've left it in EC for a similar reason)
- PreAllocatedDefault can be removed in favor of Default; etc.
- ExecutionContext.Capture itself checks whether flow is suppressed; doing a check before it adds a TLS lookup and in doing so optimizes for an uncommon case in exchange for making the common case more expensive.  I've removed those checks.

And in the process, I also noticed that several lazily initialized delegates that no longer need to be, and cleaned those up.  These were lazy due to needing to be for security checks that aren't relevant in coreclr.

Commit migrated from https://github.com/dotnet/coreclr/commit/b72fc3aa651ffdeb9136f785fc7631663a92685f

src/coreclr/src/mscorlib/src/System/IO/Stream.cs
src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
src/coreclr/src/mscorlib/src/System/Threading/ExecutionContext.cs
src/coreclr/src/mscorlib/src/System/Threading/Overlapped.cs
src/coreclr/src/mscorlib/src/System/Threading/Tasks/Task.cs
src/coreclr/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
src/coreclr/src/mscorlib/src/System/Threading/Thread.cs
src/coreclr/src/mscorlib/src/System/Threading/ThreadPool.cs
src/coreclr/src/mscorlib/src/System/Threading/Timer.cs

index a7dbe48..371c650 100644 (file)
@@ -679,7 +679,7 @@ namespace System.IO {
                     var invokeAsyncCallback = s_invokeAsyncCallback;
                     if (invokeAsyncCallback == null) s_invokeAsyncCallback = invokeAsyncCallback = InvokeAsyncCallback; // benign race condition
 
-                    using(context) ExecutionContext.Run(context, invokeAsyncCallback, this, true);
+                    ExecutionContext.Run(context, invokeAsyncCallback, this);
                 }
             }
 
index 5952740..35ccdac 100644 (file)
@@ -876,12 +876,12 @@ namespace System.Runtime.CompilerServices
             Debugger.NotifyOfCrossThreadDependency();
 
             // The builder needs to flow ExecutionContext, so capture it.
-            var capturedContext = ExecutionContext.FastCapture(); // ok to use FastCapture as we haven't made any permission demands/asserts
+            var capturedContext = ExecutionContext.Capture();
 
             // If the ExecutionContext is the default context, try to use a cached delegate, creating one if necessary.
             Action action;
             MoveNextRunner runner;
-            if (capturedContext != null && capturedContext.IsPreAllocatedDefault)
+            if (capturedContext == ExecutionContext.Default)
             {
                 // Get the cached delegate, and if it's non-null, return it.
                 action = m_defaultContextAction;
@@ -1016,12 +1016,8 @@ namespace System.Runtime.CompilerServices
 
                 if (m_context != null)
                 {
-                    try
-                    {
-                        // Use the context and callback to invoke m_stateMachine.MoveNext.
-                        ExecutionContext.Run(m_context, InvokeMoveNextCallback, m_stateMachine, preserveSyncCtx: true);
-                    }
-                    finally { m_context.Dispose(); }
+                    // Use the context and callback to invoke m_stateMachine.MoveNext.
+                    ExecutionContext.Run(m_context, InvokeMoveNextCallback, m_stateMachine);
                 }
                 else
                 {
@@ -1046,24 +1042,11 @@ namespace System.Runtime.CompilerServices
             internal void RunWithDefaultContext()
             {
                 Debug.Assert(m_stateMachine != null, "The state machine must have been set before calling Run.");
-                ExecutionContext.Run(ExecutionContext.PreAllocatedDefault, InvokeMoveNextCallback, m_stateMachine, preserveSyncCtx: true);
+                ExecutionContext.Run(ExecutionContext.Default, InvokeMoveNextCallback, m_stateMachine);
             }
 
             /// <summary>Gets a delegate to the InvokeMoveNext method.</summary>
-            protected static ContextCallback InvokeMoveNextCallback
-            {
-                get { return s_invokeMoveNext ?? (s_invokeMoveNext = InvokeMoveNext); }
-            }
-
-            /// <summary>Cached delegate used with ExecutionContext.Run.</summary>
-            private static ContextCallback s_invokeMoveNext; // lazily-initialized due to SecurityCritical attribution
-
-            /// <summary>Invokes the MoveNext method on the supplied IAsyncStateMachine.</summary>
-            /// <param name="stateMachine">The IAsyncStateMachine machine instance.</param>
-            private static void InvokeMoveNext(object stateMachine)
-            {
-                ((IAsyncStateMachine)stateMachine).MoveNext();
-            }
+            protected static readonly ContextCallback InvokeMoveNextCallback = sm => ((IAsyncStateMachine)sm).MoveNext();
         }
 
         /// <summary>
index 5ea9942..7baddff 100644 (file)
@@ -55,7 +55,7 @@ namespace System.Threading
     [Serializable]
     public sealed class ExecutionContext : IDisposable, ISerializable
     {
-        private static readonly ExecutionContext Default = new ExecutionContext();
+        internal static readonly ExecutionContext Default = new ExecutionContext();
 
         private readonly IAsyncLocalValueMap m_localValues;
         private readonly IAsyncLocal[] m_localChangeNotifications;
@@ -93,16 +93,10 @@ namespace System.Threading
         public static ExecutionContext Capture()
         {
             ExecutionContext executionContext = Thread.CurrentThread.ExecutionContext;
-            if (executionContext == null)
-            {
-                return Default;
-            }
-            if (executionContext.m_isFlowSuppressed)
-            {
-                // Prevent ExecutionContext.Run on a suppressed-flow context for desktop framework compatibility
-                return null;
-            }
-            return executionContext;
+            return
+                executionContext == null ? Default :
+                executionContext.m_isFlowSuppressed ? null :
+                executionContext;
         }
 
         private ExecutionContext ShallowClone(bool isFlowSuppressed)
@@ -301,21 +295,6 @@ namespace System.Threading
             }
         }
 
-    #region Wrappers for CLR compat, to avoid ifdefs all over the BCL
-
-        [Flags]
-        internal enum CaptureOptions
-        {
-            None = 0x00,
-            IgnoreSyncCtx = 0x01,
-            OptimizeDefaultCase = 0x02,
-        }
-
-        internal static ExecutionContext Capture(ref StackCrawlMark stackMark, CaptureOptions captureOptions)
-        {
-            return Capture();
-        }
-
         [FriendAccessAllowed]
         internal static ExecutionContext FastCapture()
         {
@@ -328,11 +307,6 @@ namespace System.Threading
             Run(executionContext, callback, state);
         }
 
-        internal bool IsDefaultFTContext(bool ignoreSyncCtx)
-        {
-            return this == Default;
-        }
-
         public ExecutionContext CreateCopy()
         {
             return this; // since CoreCLR's ExecutionContext is immutable, we don't need to create copies.
@@ -342,18 +316,6 @@ namespace System.Threading
         {
             // For CLR compat only
         }
-
-        internal static ExecutionContext PreAllocatedDefault
-        {
-            get { return ExecutionContext.Default; }
-        }
-
-        internal bool IsPreAllocatedDefault
-        {
-            get { return this == ExecutionContext.Default; }
-        }
-
-    #endregion
     }
 
     public struct AsyncFlowControl : IDisposable
index 2b192c7..129bea6 100644 (file)
@@ -71,13 +71,11 @@ namespace System.Threading
         {
         }
 
-        internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback, ref StackCrawlMark stackMark)
+        internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback)
         {
             _ioCompletionCallback = ioCompletionCallback;
             // clone the exection context
-            _executionContext = ExecutionContext.Capture(
-                ref stackMark, 
-                ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
+            _executionContext = ExecutionContext.Capture();
         }
         // Context callback: same sig for SendOrPostCallback and ContextCallback
         static internal ContextCallback _ccb = new ContextCallback(IOCompletionCallback_Context);
@@ -103,26 +101,23 @@ namespace System.Threading
                 overlapped = OverlappedData.GetOverlappedFromNative(pOVERLAP).m_overlapped;
                 helper  = overlapped.iocbHelper;
 
-            if (helper == null || helper._executionContext == null || helper._executionContext.IsDefaultFTContext(true))
-            {
-                // We got here because of UnsafePack (or) Pack with EC flow supressed
-                IOCompletionCallback callback = overlapped.UserCallback;
-                callback( errorCode,  numBytes,  pOVERLAP);
-            }
-            else
-            {
-                // We got here because of Pack
-                helper._errorCode = errorCode;
-                helper._numBytes = numBytes;
-                helper._pOVERLAP = pOVERLAP;
-                    using (ExecutionContext executionContext = helper._executionContext.CreateCopy())
-                    ExecutionContext.Run(executionContext, _ccb, helper, true);
-            }                    
-
-                    //Quickly check the VM again, to see if a packet has arrived.
-
+                if (helper == null || helper._executionContext == null || helper._executionContext == ExecutionContext.Default)
+                {
+                    // We got here because of UnsafePack (or) Pack with EC flow supressed
+                    IOCompletionCallback callback = overlapped.UserCallback;
+                    callback( errorCode,  numBytes,  pOVERLAP);
+                }
+                else
+                {
+                    // We got here because of Pack
+                    helper._errorCode = errorCode;
+                    helper._numBytes = numBytes;
+                    helper._pOVERLAP = pOVERLAP;
+                    ExecutionContext.Run(helper._executionContext, _ccb, helper);
+                }                    
+
+                //Quickly check the VM again, to see if a packet has arrived.
                 OverlappedData.CheckVMForIOPacket(out pOVERLAP, out errorCode, out numBytes);
-
             } while (pOVERLAP != null);
 
         }
@@ -174,17 +169,15 @@ namespace System.Threading
             m_nativeOverlapped.InternalHigh = (IntPtr)0;
         }
 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
         unsafe internal NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
         {
             if (!m_pinSelf.IsNull()) {
                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_Overlapped_Pack"));
             }
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
 
             if (iocb != null)
             {
-                m_iocbHelper = new _IOCompletionCallback(iocb, ref stackMark);
+                m_iocbHelper = new _IOCompletionCallback(iocb);
                 m_iocb = iocb;
             }
             else
index 1426f71..82864aa 100644 (file)
@@ -1633,7 +1633,7 @@ namespace System.Threading.Tasks
                 }
                 else
                 {
-                    return m_contingentProperties?.m_capturedContext ?? ExecutionContext.PreAllocatedDefault;
+                    return m_contingentProperties?.m_capturedContext ?? ExecutionContext.Default;
                 }
             }
             set
@@ -1643,7 +1643,7 @@ namespace System.Threading.Tasks
                 {
                     m_stateFlags |= TASK_STATE_EXECUTIONCONTEXT_IS_NULL;
                 }
-                else if (!value.IsPreAllocatedDefault) // not the default context, then inflate the contingent properties and set it
+                else if (value != ExecutionContext.Default) // not the default context, then inflate the contingent properties and set it
                 {
                     EnsureContingentPropertiesInitializedUnsafe().m_capturedContext = value;
                 }
@@ -1651,21 +1651,6 @@ namespace System.Threading.Tasks
             }
         }
 
-        /// <summary>
-        /// Static helper function to copy specific ExecutionContext
-        /// </summary>
-        /// <param name="capturedContext">The captured context</param>
-        /// <returns>The copied context, null if the capturedContext is null</returns>
-        private static ExecutionContext CopyExecutionContext(ExecutionContext capturedContext)
-        {
-            if (capturedContext == null)
-                return null;
-            if (capturedContext.IsPreAllocatedDefault)
-                return ExecutionContext.PreAllocatedDefault;
-
-            return capturedContext.CreateCopy();
-        }
-
         /////////////
         // methods
 
@@ -2465,10 +2450,7 @@ namespace System.Threading.Tasks
                     // Run the task.  We need a simple shim that converts the
                     // object back into a Task object, so that we can Execute it.
 
-                    // Lazily initialize the callback delegate; benign race condition
-                    var callback = s_ecCallback;
-                    if (callback == null) s_ecCallback = callback = new ContextCallback(ExecutionContextCallback);
-                    ExecutionContext.Run(ec, callback, this, true);
+                    ExecutionContext.Run(ec, s_ecCallback, this);
                 }
 
                 if (AsyncCausalityTracer.LoggingOn)
@@ -2495,16 +2477,7 @@ namespace System.Threading.Tasks
             }
         }
 
-        // Cached callback delegate that's lazily initialized due to ContextCallback being SecurityCritical
-        private static ContextCallback s_ecCallback;
-
-        private static void ExecutionContextCallback(object obj)
-        {
-            Task task = obj as Task;
-            Debug.Assert(task != null, "expected a task object");
-            task.Execute();
-        }
-
+        private static readonly ContextCallback s_ecCallback = obj => ((Task)obj).Execute();
 
         /// <summary>
         /// The actual code which invokes the body of the task. This can be overriden in derived types.
index 9cf0142..3c6ccd8 100644 (file)
@@ -543,7 +543,7 @@ namespace System.Threading.Tasks
             m_action = action;
             if (flowExecutionContext)
             {
-                m_capturedContext = ExecutionContext.FastCapture();
+                m_capturedContext = ExecutionContext.Capture();
             }
         }
 
@@ -648,11 +648,7 @@ namespace System.Threading.Tasks
                     // If there is an execution context, get the cached delegate and run the action under the context.
                 else
                 {
-                    try
-                    {
-                        ExecutionContext.Run(m_capturedContext, GetInvokeActionCallback(), m_action, true);
-                    }
-                    finally { m_capturedContext.Dispose(); }
+                    ExecutionContext.Run(m_capturedContext, GetInvokeActionCallback(), m_action);
                 }
             }
             finally
@@ -667,8 +663,7 @@ namespace System.Threading.Tasks
         void IThreadPoolWorkItem.ExecuteWorkItem()
         {
             // inline the fast path
-            if (m_capturedContext == null && !TplEtwProvider.Log.IsEnabled()
-            )
+            if (m_capturedContext == null && !TplEtwProvider.Log.IsEnabled())
             {
                 m_action();
             }
@@ -717,7 +712,7 @@ namespace System.Threading.Tasks
                 // If there's no captured context, just run the callback directly.
                 if (m_capturedContext == null) callback(state);
                 // Otherwise, use the captured context to do so.
-                else ExecutionContext.Run(m_capturedContext, callback, state, true);
+                else ExecutionContext.Run(m_capturedContext, callback, state);
             }
             catch (Exception exc) // we explicitly do not request handling of dangerous exceptions like AVs
             {
@@ -727,9 +722,6 @@ namespace System.Threading.Tasks
             {
                 // Restore the current task information
                 if (prevCurrentTask != null) currentTask = prevCurrentTask;
-
-                // Clean up after the execution context, which is only usable once.
-                if (m_capturedContext != null) m_capturedContext.Dispose();
             }
         }
 
index bfa47f7..f05e104 100644 (file)
@@ -280,9 +280,7 @@ namespace System.Threading {
                 // If we reach here with a null delegate, something is broken. But we'll let the StartInternal method take care of
                 // reporting an error. Just make sure we dont try to dereference a null delegate.
                 ThreadHelper t = (ThreadHelper)(m_Delegate.Target);
-                ExecutionContext ec = ExecutionContext.Capture(
-                    ref stackMark,
-                    ExecutionContext.CaptureOptions.IgnoreSyncCtx);
+                ExecutionContext ec = ExecutionContext.Capture();
                 t.SetExecutionContextHelper(ec);
             }
 
index 67701ec..8076a76 100644 (file)
@@ -951,7 +951,7 @@ namespace System.Threading
             }
             else
             {
-                ExecutionContext.Run(context, ccb, this, preserveSyncCtx:true);
+                ExecutionContext.Run(context, ccb, this);
             }
         }
 
@@ -1010,7 +1010,7 @@ namespace System.Threading
 #if DEBUG
             MarkExecuted(aborted:false);
 #endif
-            ExecutionContext.Run(ExecutionContext.PreAllocatedDefault, ccb, this, preserveSyncCtx:true);
+            ExecutionContext.Run(ExecutionContext.Default, ccb, this);
         }
 
         void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
@@ -1042,17 +1042,15 @@ namespace System.Threading
         private static readonly ContextCallback _ccbt = new ContextCallback(WaitOrTimerCallback_Context_t);
         private static readonly ContextCallback _ccbf = new ContextCallback(WaitOrTimerCallback_Context_f);
 
-        internal _ThreadPoolWaitOrTimerCallback(WaitOrTimerCallback waitOrTimerCallback, Object state, bool compressStack, ref StackCrawlMark stackMark)
+        internal _ThreadPoolWaitOrTimerCallback(WaitOrTimerCallback waitOrTimerCallback, Object state, bool compressStack)
         {
             _waitOrTimerCallback = waitOrTimerCallback;
             _state = state;
 
-            if (compressStack && !ExecutionContext.IsFlowSuppressed())
+            if (compressStack)
             {
                 // capture the exection context
-                _executionContext = ExecutionContext.Capture(
-                    ref stackMark,
-                    ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
+                _executionContext = ExecutionContext.Capture();
             }
         }
         
@@ -1081,10 +1079,7 @@ namespace System.Threading
             }
             else
             {
-                using (ExecutionContext executionContext = helper._executionContext.CreateCopy())
-                {
-                    ExecutionContext.Run(executionContext, timedOut ? _ccbt : _ccbf, helper, preserveSyncCtx:true);
-                }
+                ExecutionContext.Run(helper._executionContext, timedOut ? _ccbt : _ccbf, helper);
             }
         }    
 
@@ -1167,7 +1162,7 @@ namespace System.Threading
 
             if (callBack != null)
             {
-                _ThreadPoolWaitOrTimerCallback callBackHelper = new _ThreadPoolWaitOrTimerCallback(callBack, state, compressStack, ref stackMark);
+                _ThreadPoolWaitOrTimerCallback callBackHelper = new _ThreadPoolWaitOrTimerCallback(callBack, state, compressStack);
                 state = (Object)callBackHelper;
                 // call SetWaitObject before native call so that waitObject won't be closed before threadpoolmgr registration
                 // this could occur if callback were to fire before SetWaitObject does its addref
@@ -1303,7 +1298,7 @@ namespace System.Threading
 
             ExecutionContext context = ExecutionContext.Capture();
 
-            IThreadPoolWorkItem tpcallBack = context == ExecutionContext.PreAllocatedDefault ?
+            IThreadPoolWorkItem tpcallBack = context == ExecutionContext.Default ?
                 new QueueUserWorkItemCallbackDefaultContext(callBack, state) :
                 (IThreadPoolWorkItem)new QueueUserWorkItemCallback(callBack, state, context);
 
index a2b4378..263e47a 100644 (file)
@@ -435,19 +435,13 @@ namespace System.Threading
         volatile WaitHandle m_notifyWhenNoCallbacksRunning;
 
 
-        internal TimerQueueTimer(TimerCallback timerCallback, object state, uint dueTime, uint period, ref StackCrawlMark stackMark)
+        internal TimerQueueTimer(TimerCallback timerCallback, object state, uint dueTime, uint period)
         {
             m_timerCallback = timerCallback;
             m_state = state;
             m_dueTime = Timeout.UnsignedInfinite;
             m_period = Timeout.UnsignedInfinite;
-
-            if (!ExecutionContext.IsFlowSuppressed())
-            {
-                m_executionContext = ExecutionContext.Capture(
-                    ref stackMark,
-                    ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
-            }
+            m_executionContext = ExecutionContext.Capture();
 
             //
             // After the following statement, the timer may fire.  No more manipulation of timer state outside of
@@ -601,29 +595,15 @@ namespace System.Threading
             }
             else
             {
-                using (ExecutionContext executionContext = 
-                    m_executionContext.IsPreAllocatedDefault ? m_executionContext : m_executionContext.CreateCopy())
-                {
-                    ContextCallback callback = s_callCallbackInContext;
-                    if (callback == null)
-                        s_callCallbackInContext = callback = new ContextCallback(CallCallbackInContext);
-                    
-                    ExecutionContext.Run(
-                        executionContext,
-                        callback,
-                        this,  // state
-                        true); // ignoreSyncCtx
-                }
+                ExecutionContext.Run(m_executionContext, s_callCallbackInContext, this);
             }
         }
 
-        private static ContextCallback s_callCallbackInContext;
-
-        private static void CallCallbackInContext(object state)
+        private static readonly ContextCallback s_callCallbackInContext = state =>
         {
             TimerQueueTimer t = (TimerQueueTimer)state;
             t.m_timerCallback(t.m_state);
-        }
+        };
     }
 
     //
@@ -686,7 +666,6 @@ namespace System.Threading
 
         private TimerHolder m_timer;
 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
         public Timer(TimerCallback callback, 
                      Object        state,  
                      int           dueTime,
@@ -697,12 +676,10 @@ namespace System.Threading
             if (period < -1 )
                 throw new ArgumentOutOfRangeException(nameof(period), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
             Contract.EndContractBlock();
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
 
-            TimerSetup(callback,state,(UInt32)dueTime,(UInt32)period,ref stackMark);
+            TimerSetup(callback,state,(UInt32)dueTime,(UInt32)period);
         }
 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
         public Timer(TimerCallback callback, 
                      Object        state,  
                      TimeSpan      dueTime,
@@ -720,22 +697,18 @@ namespace System.Threading
             if (periodTm > MAX_SUPPORTED_TIMEOUT)
                 throw new ArgumentOutOfRangeException(nameof(periodTm),Environment.GetResourceString("ArgumentOutOfRange_PeriodTooLarge"));
 
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
-            TimerSetup(callback,state,(UInt32)dueTm,(UInt32)periodTm,ref stackMark);
+            TimerSetup(callback,state,(UInt32)dueTm,(UInt32)periodTm);
         }
 
         [CLSCompliant(false)]
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
         public Timer(TimerCallback callback, 
                      Object        state,  
                      UInt32        dueTime,
                      UInt32        period)
         {
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
-            TimerSetup(callback,state,dueTime,period,ref stackMark);
+            TimerSetup(callback,state,dueTime,period);
         }
 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable                                        
         public Timer(TimerCallback callback, 
                      Object        state,  
                      long          dueTime,
@@ -750,11 +723,9 @@ namespace System.Threading
             if (period > MAX_SUPPORTED_TIMEOUT)
                 throw new ArgumentOutOfRangeException(nameof(period),Environment.GetResourceString("ArgumentOutOfRange_PeriodTooLarge"));
             Contract.EndContractBlock();
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
-            TimerSetup(callback,state,(UInt32) dueTime, (UInt32) period,ref stackMark);
+            TimerSetup(callback,state,(UInt32) dueTime, (UInt32) period);
         }
 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
         public Timer(TimerCallback callback)
         {
             int dueTime = -1;    // we want timer to be registered, but not activated.  Requires caller to call
@@ -762,21 +733,19 @@ namespace System.Threading
                                 // for a timer to be fired before the returned value is assigned to the variable,
                                 // potentially causing the callback to reference a bogus value (if passing the timer to the callback). 
             
-            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
-            TimerSetup(callback, this, (UInt32)dueTime, (UInt32)period, ref stackMark);
+            TimerSetup(callback, this, (UInt32)dueTime, (UInt32)period);
         }
 
         private void TimerSetup(TimerCallback callback,
                                 Object state, 
                                 UInt32 dueTime,
-                                UInt32 period,
-                                ref StackCrawlMark stackMark)
+                                UInt32 period)
         {
             if (callback == null)
                 throw new ArgumentNullException(nameof(TimerCallback));
             Contract.EndContractBlock();
 
-            m_timer = new TimerHolder(new TimerQueueTimer(callback, state, dueTime, period, ref stackMark));
+            m_timer = new TimerHolder(new TimerQueueTimer(callback, state, dueTime, period));
         }
      
         public bool Change(int dueTime, int period)