//
// Copyright (c) Microsoft Corporation.   All rights reserved.
//

/*******************************************************************/
/*                           WARNING                               */
/* This file should be identical in the Bartok and Singularity     */
/* depots. Master copy resides in Bartok Depot. Changes should be  */
/* made to Bartok Depot and propagated to Singularity Depot.       */
/*******************************************************************/

namespace System.GCs
{
    using System.Runtime.CompilerServices;
    using System.Threading;

#if SINGULARITY
    using Microsoft.Singularity;
#endif
#if SINGULARITY_KERNEL
    using Microsoft.Singularity.Scheduling;
#endif

    [AccessedByRuntime("Referenced in halforgc.asm")]
    internal class Transitions
    {

        // Synchronization among threads for GC:
        //
        // We keep an integer for each thread.
        // The possible values are:

#if SINGULARITY_KERNEL
        // Thread is dormant or in unmanaged code and a GC would be ok
        [AccessedByRuntime("Referenced in halforgc.asm")]
        private const int DormantState      =   0x1;
        // Thread is running in managed code and not ready for GC
        [AccessedByRuntime("Referenced in halforgc.asm")]
        private const int MutatorState      =   0x2;
        // GC work is desired
        private const int GCRequest         =   0x4;
        // Thread is under GC control
        private const int GCControl         =   0x8;
        // Thread is dormant in the application space
        [AccessedByRuntime("Referenced in halforgc.asm")]
        private const int OtherDormantState =  0x10;
        // Thread is running in the application space
        [AccessedByRuntime("Referenced in halforgc.asm")]
        private const int OtherMutatorState =  0x20;
        // GC work is desired in the application space
        private const int OtherGCRequest    =  0x40;
        // Application thread is under GC control
        private const int OtherGCControl    =  0x80;
#else
        // Thread is dormant or in unmanaged code and a GC would be ok
        [AccessedByRuntime("Referenced in halforgc.asm")]
        private const int DormantState      =  0x10;
        // Thread is running in managed code and not ready for GC
        [AccessedByRuntime("Referenced in halforgc.asm")]
        private const int MutatorState      =  0x20;
        // GC work is desired.  Must be a power of 2.
        private const int GCRequest         =  0x40;
        // Thread is under GC control.  Must be a power of 2.
        private const int GCControl         =  0x80;
        // Thread is dormant in the kernel space
        [AccessedByRuntime("Referenced in halforgc.asm")]
        private const int OtherDormantState =   0x1;
        // Thread is running in the kernel space
        [AccessedByRuntime("Referenced in halforgc.asm")]
        private const int OtherMutatorState =   0x2;
#endif // SINGULARITY_KERNEL

        internal static bool        fInitializedRuntime;

        internal static void RuntimeInitialized() {
            fInitializedRuntime = true;
        }

#if SINGULARITY_KERNEL
        [Inline]
        internal static unsafe
        void InitializeStatusWord(ref ThreadContext threadContext)
        {
            int oldValue, newValue;
            do {
                oldValue = threadContext.gcStates;
                newValue = ((oldValue|DormantState|OtherDormantState)&
                            ~(MutatorState|GCRequest|GCControl|
                              OtherMutatorState|OtherGCRequest|OtherGCControl));
            } while (!CompareAndSwap(ref threadContext.gcStates,
                                     newValue, oldValue));
        }
#endif

        // Code outside of the GC will move threads between
        // MutatorState and DormantState.  This should be done with
        // the TakeMutatorControl and TakeDormantControl methods.  The
        // garbage collectors can request that they be notified when
        // threads go dormant.  They do this by calling the
        // MakeGCRequests method.  The TakeMutatorControl and
        // TakeDormantControl methods are then supposed to do the
        // right thing.

        [Inline]
        private static bool CompareAndSwap(ref int word,
                                           int newValue,
                                           int oldValue)
        {
            return (Interlocked.CompareExchange(ref word, newValue, oldValue)
                    == oldValue);
        }

        #region Transition Methods (Methods corresponding to macro transitions)

        // To be called when a thread is created
        internal static void NewThreadNotification(int newThreadIndex,
                                                   bool initial)
        {
#if SINGULARITY_PROCESS
            if (initial) {
                VTable.Assert(InMutatorState(newThreadIndex));
                return;
            }
#endif
            VTable.Assert(InDormantState(newThreadIndex));
        }

        // To be called when a thread is terminated/terminating
        internal static void DeadThreadNotification(int deadThreadIndex)
        {
            VTable.Assert(Thread.threadTable[deadThreadIndex] == null);
            VTable.Assert(InDormantState(deadThreadIndex));
            if (Transitions.HasGCRequest(deadThreadIndex)) {
                GC.ThreadDormantGCNotification(deadThreadIndex);
            }
        }

#if SINGULARITY
#if SINGULARITY_KERNEL
        // To be called at the beginning of a thread
        internal static unsafe void ThreadStart() {
            ThreadContext *currentThreadContext =
                Processor.GetCurrentThreadContext();
            TakeInitialMutatorControl(currentThreadContext);
        }
#else
        // To be called at the beginning of a thread
        internal static unsafe void ThreadStart() {
            ThreadContext *currentThreadContext =
                Processor.GetCurrentThreadContext();
            // The thread has been started in the kernel.  We need
            // to ensure that the transition to application space
            // is completed properly.
            EnsureMutatorControlNoGC(currentThreadContext);
        }
#endif

#else // SINGULARITY

        // To be called at the beginning of a thread
        internal static void ThreadStart(int currentThreadIndex) {
            VTable.Assert(InDormantState(currentThreadIndex));
            TakeInitialMutatorControl(currentThreadIndex);
        }

#endif // SINGULARITY

        // To be called at the end of a thread
        internal static void ThreadEnd(int currentThreadIndex) {
            VTable.Assert(InMutatorState(currentThreadIndex));
            TakeDormantControl(currentThreadIndex);
        }

#if SINGULARITY

        [AccessedByRuntime("called from halforgc.asm")]
        [NoStackLinkCheckTrans] // This is called from __pushStackMark, which cannot tolerate an 
                                // ABI call to allocate a new stack
        internal static unsafe
        void LeaveManagedSpace(ThreadContext *currentThreadContext)
        {
            TransferMutatorControl(currentThreadContext);
        }

        // To be used for returning from calls to outside managed space
        [AccessedByRuntime("called from halforgc.asm")]
        [NoStackLinkCheckTrans] // This is called from __popStackMark, which cannot tolerate an 
                                // ABI call to allocate a new stack
        [Inline]
        internal static unsafe
        void ReturnToManagedSpace(ThreadContext *currentThreadContext)
        {
            EnsureMutatorControl(currentThreadContext);
        }

#if SINGULARITY_KERNEL

        [AccessedByRuntime("called from halforgc.asm")]
        internal static unsafe
        void SuspendThread(ThreadContext *currentThreadContext)
        {
            TakeDormantControl(currentThreadContext);
        }

        [AccessedByRuntime("called from halforgc.asm")]
        internal static unsafe
        void ReviveThread(ThreadContext *currentThreadContext)
        {
            TakeMutatorControl(currentThreadContext);
        }

#endif // SINGULARITY_KERNEL

#else // SINGULARITY

        // To be used for calls to outside managed space
        [AccessedByRuntime("called from halforgc.asm")]
        [Inline]
        [ManualRefCounts]
        internal static void LeaveManagedSpace(Thread currentThread) {
            TakeDormantControl(currentThread.threadIndex);
        }

        // To be used for returning from calls to outside managed space
        [AccessedByRuntime("called from halforgc.asm")]
        [Inline]
        internal static Thread ReturnToManagedSpace(int currentThreadIndex) {
            TakeMutatorControl(currentThreadIndex);
            return Thread.threadTable[currentThreadIndex];
        }

#endif // SINGULARITY

        // For the LoadFunction stub for PInvoke methods
        [RequiredByBartok]
        internal static void EnterLoadFunctionStub() {
            TakeMutatorControl(Thread.GetCurrentThreadIndex());
        }

        // For the LoadFunction stub for PInvoke methods
        [RequiredByBartok]
        internal static void LeaveLoadFunctionStub() {
            TakeDormantControl(Thread.GetCurrentThreadIndex());
        }

        #endregion

        internal static void MakeGCRequests(int excludedThreadIndex) {
            int limit = Thread.threadTable.Length;
            for (int i = 0; i < limit; i++) {
                if (Thread.threadTable[i] != null &&
                    i != excludedThreadIndex) {
                    MakeGCRequest(i);
                }
            }
        }

        #region Helper Functions (Independent of where statusWord is)

        [Inline]
        [NoHeapAllocation]
        private static bool fInDormantState(int statusWord) {
            return ((statusWord & DormantState) != 0);
        }

        [Inline]
        [NoHeapAllocation]
        private static bool fInMutatorState(int statusWord) {
            return ((statusWord & MutatorState) != 0);
        }

        [Inline]
        [NoHeapAllocation]
        private static bool fHasGCRequest(int statusWord) {
            return ((statusWord & GCRequest) != 0);
        }

        [Inline]
        [NoHeapAllocation]
        private static bool fUnderGCControl(int statusWord) {
            return ((statusWord & GCControl) != 0);
        }

        [Inline]
        private static void TakeDormantControl(ref int statusWord,
                                               int threadIndex)
        {
            VTable.Assert(fInMutatorState(statusWord));
            VTable.Deny(fInDormantState(statusWord));
            int oldValue, newValue;
            do {
                oldValue = statusWord;
                newValue = (oldValue|DormantState) & ~MutatorState;
            } while (!CompareAndSwap(ref statusWord, newValue, oldValue));
            if (fHasGCRequest(newValue)) {
                GC.ThreadDormantGCNotification(threadIndex);
            }
        }

        [Inline]
        private static void TakeDormantControlNoGC(ref int statusWord) {
            VTable.Assert(fInMutatorState(statusWord));
            VTable.Deny(fInDormantState(statusWord));
            int oldValue, newValue;
            do {
                oldValue = statusWord;
                newValue = (oldValue|DormantState) & ~MutatorState;
            } while (!CompareAndSwap(ref statusWord, newValue, oldValue));
        }

        [Inline]
        private static void TransferMutatorControl(ref int statusWord,
                                                   int threadIndex)
        {
            if (!CompareAndSwap(ref statusWord,
                                DormantState|OtherMutatorState,
                                MutatorState|OtherDormantState)) {
                TakeDormantControl(ref statusWord, threadIndex);
            }
        }

        [Inline]
        private static void EnsureMutatorControl(ref int statusWord,
                                                 int currentThreadIndex)
        {
            if (!fInMutatorState(statusWord)) {
                TakeMutatorControl(ref statusWord, currentThreadIndex);
            }
            VTable.Deny(fInDormantState(statusWord));
            VTable.Deny(fUnderGCControl(statusWord));
        }

        [Inline]
        private static void EnsureMutatorControlNoGC(ref int statusWord,
                                                     int currentThreadIndex)
        {
            if (!fInMutatorState(statusWord)) {
                TakeMutatorControlNoGC(ref statusWord, currentThreadIndex);
            }
            VTable.Deny(fInDormantState(statusWord));
            VTable.Deny(fUnderGCControl(statusWord));
        }

#if SINGULARITY
        [AccessedByRuntime("referenced from halasm.asm")]
        [NoStackLinkCheckTrans]
        internal static unsafe void RestoreMutatorControlIfNeeded()
        {
            ThreadContext *currentThreadContext =
                Processor.GetCurrentThreadContext();
            if (!Transitions.InMutatorState(currentThreadContext)) {
                // NOTE: There is a window where OtherMutatorControl may be
                // set simultaneously with OtherGCRequest.  When clearing
                // OtherMutatorControl and setting OtherDormantControl, the
                // normal thing to do is to check for a GC request, but in
                // this case it doesn't matter as this code is only run
                // when an kernel exception is supposed to pass over an
                // application stack segment.
                int oldValue, newValue;
                bool consumedSignal = false;
                int threadIndex = currentThreadContext->threadIndex;
                do {
                    oldValue = currentThreadContext->gcStates;
                    if (fUnderGCControl(oldValue)) {
                        Thread.WaitForGCEvent(threadIndex);
                        consumedSignal = true;
                    }
                    newValue = ((oldValue|MutatorState|OtherDormantState) &
                                ~(DormantState|OtherMutatorState));
                } while (!CompareAndSwap(ref currentThreadContext->gcStates,
                                         newValue, oldValue));
                if (consumedSignal) {
                    Thread.SignalGCEvent(threadIndex);
                }
            }
        }
#endif

        [Inline]
        private static void TakeMutatorControl(ref int statusWord,
                                               int currentThreadIndex)
        {
            if (!SwitchToMutatorState(ref statusWord)) {
                TakeMutatorControlSlow(ref statusWord, currentThreadIndex);
            }
            VTable.Assert(fInMutatorState(statusWord));
            VTable.Deny(fInDormantState(statusWord));
            VTable.Deny(fUnderGCControl(statusWord));
        }

        [Inline]
        private static void TakeMutatorControlNoGC(ref int statusWord,
                                                   int currentThreadIndex)
        {
            if (!SwitchToMutatorState(ref statusWord)) {
                TakeMutatorControlSlowNoGC(ref statusWord, currentThreadIndex);
            }
            VTable.Assert(fInMutatorState(statusWord));
            VTable.Deny(fInDormantState(statusWord));
            VTable.Deny(fUnderGCControl(statusWord));
        }

        private static void TakeInitialMutatorControl(ref int statusWord,
                                                      int currentThreadIndex)
        {
            if (!SwitchToMutatorState(ref statusWord)) {
                TakeInitialMutatorControlSlow(ref statusWord,
                                              currentThreadIndex);
            }
            VTable.Assert(fInMutatorState(statusWord));
            VTable.Deny(fInDormantState(statusWord));
            VTable.Deny(fUnderGCControl(statusWord));
        }

        [NoInline]
        // [StackLinkCheck] Removed due to call from ReturnToManagedSpace
        private static void TakeMutatorControlSlow(ref int statusWord,
                                                   int currentThreadIndex)
        {
            TakeMutatorControlSlow(ref statusWord, currentThreadIndex,
                                   true, true);
        }

        [NoInline]
        // [StackLinkCheck] Removed due to call from LeaveManagedSpace
        private static void TakeMutatorControlSlowNoGC(ref int statusWord,
                                                       int currentThreadIndex)
        {
            TakeMutatorControlSlow(ref statusWord, currentThreadIndex,
                                   false, true);
        }

        private static
        void TakeInitialMutatorControlSlow(ref int statusWord,
                                           int currentThreadIndex)
        {
            TakeMutatorControlSlow(ref statusWord, currentThreadIndex,
                                   false, false);
        }

        private static void TakeMutatorControlSlow(ref int statusWord,
                                                   int currentThreadIndex,
                                                   bool allowGC,
                                                   bool preserveSignals)
        {
            bool consumedSignal = false;
            while (true) {
                if (SwitchToMutatorState(ref statusWord)) {
                    break;
                }
                if (SwitchToMutatorStateWithGCRequest(ref statusWord)) {
                    if (allowGC) {
                        Thread currentThread =
                            Thread.threadTable[currentThreadIndex];
                        if (currentThread != null) {
                            GC.InvokeCollection(currentThread);
                        }
                    }
                    break;
                }
                if (fUnderGCControl(statusWord)) {
                    Thread.WaitForGCEvent(currentThreadIndex);
                    consumedSignal = true;
                }
            }
            if (consumedSignal && preserveSignals) {
                Thread.SignalGCEvent(currentThreadIndex);
            }
        }

        [Inline]
        private static bool SwitchToMutatorState(ref int statusWord) {
            VTable.Deny(fInMutatorState(statusWord),
                        "Thread is already under mutator control");
            VTable.Assert(fInDormantState(statusWord));
            int oldValue = statusWord & ~(GCRequest|GCControl);
            int newValue = (oldValue|MutatorState) & ~DormantState;
            return CompareAndSwap(ref statusWord, newValue, oldValue);
        }

        [Inline]
        private static
        bool SwitchToMutatorStateWithGCRequest(ref int statusWord)
        {
            int oldValue = ((statusWord|DormantState|GCRequest) & ~GCControl);
            int newValue = (oldValue|MutatorState) & ~DormantState;
            return CompareAndSwap(ref statusWord, newValue, oldValue);
        }

        [Inline]
        private static bool TakeGCControl(ref int statusWord) {
            int oldValue, newValue;
            do {
                oldValue = statusWord;
                if (!fInDormantState(oldValue) ||
                    !fHasGCRequest(oldValue) ||
                    fUnderGCControl(oldValue)) {
                    return false;
                }
                newValue = oldValue|GCControl;
            } while (!CompareAndSwap(ref statusWord, newValue, oldValue));
            return true;
        }

        [Inline]
        private static void ReleaseGCControl(ref int statusWord,
                                             int threadIndex)
        {
            // There is only one possible transition out of this state.
            int oldValue, newValue;
            do {
                oldValue = statusWord;
                VTable.Assert(fInDormantState(oldValue));
                VTable.Assert(fHasGCRequest(oldValue));
                VTable.Assert(fUnderGCControl(oldValue));
                newValue = (oldValue& ~(GCRequest|GCControl));
            } while (!CompareAndSwap(ref statusWord, newValue, oldValue));
            Thread.SignalGCEvent(threadIndex);
        }

        private static void MakeGCRequest(ref int statusWord,
                                          int threadIndex)
        {
#if SINGULARITY_KERNEL
            if (Scheduler.IsIdleThread(threadIndex)) {
                return;
            }
#endif
            int oldStatus, newStatus;
            do {
                oldStatus = statusWord;
                newStatus = oldStatus|GCRequest;
            } while (!CompareAndSwap(ref statusWord, newStatus, oldStatus));
        }

        private static void ClearGCRequest(ref int statusWord,
                                           int threadIndex)
        {
            VTable.Assert(fHasGCRequest(statusWord));
            VTable.Assert(fInMutatorState(statusWord));
            int oldStatus, newStatus;
            do {
                oldStatus = statusWord;
                newStatus = (oldStatus & ~GCRequest);
            } while (!CompareAndSwap(ref statusWord, newStatus, oldStatus));
        }

        #endregion

#if SINGULARITY

        [Inline]
        private static unsafe
        ThreadContext *GetCurrentThreadContext(int currentThreadIndex) {
            VTable.Assert(GetThreadContext(currentThreadIndex) ==
                          Processor.GetCurrentThreadContext());
            return Processor.GetCurrentThreadContext();
        }

        [Inline]
        private static unsafe
        ThreadContext *GetThreadContext(int threadIndex) {
            Thread thread = Thread.threadTable[threadIndex];
            if (thread == null) {
                return null;
            } else {
#if SINGULARITY_KERNEL
                fixed (ThreadContext *result = &thread.context) {
                    return result;
                }
#else
                return thread.context;
#endif
            }
        }

#endif

        #region Dependent (Methods depending on location of the status word)

#if SINGULARITY

        [NoBarriers]
        [PreInitRefCounts]
        internal static void Initialize()
        {
        }

        // To be used for callbacks into managed space
        [RequiredByBartok]
        [Inline]
        internal static unsafe void EntryIntoManagedSpace() {
            ThreadContext *currentThreadContext =
                Processor.GetCurrentThreadContext();
            EnsureMutatorControl(currentThreadContext);
        }

        // To be used for returning from a callback into managed space
        [RequiredByBartok]
        [Inline]
        internal static unsafe void ReturnFromManagedSpace() {
            ThreadContext *currentThreadContext =
                Processor.GetCurrentThreadContext();
#if SINGULARITY_KERNEL
            // In Singularity kernel this function is the exit point of a kernel ABI.
            // If the thread is requested to be aborted, we stop it right here
            currentThreadContext->thread.ProcessAbortIfRequested(AbortRequestSource.ABIExit);
#endif
            TransferMutatorControl(currentThreadContext);
        }

        // To be used for returning from a callback into managed space
        // from another managed space that doesn't want the automatic
        // transition back to its mutator state.
        [RequiredByBartok]
        [Inline]
        internal static unsafe void ReturnFromManagedSpaceNoCallerTransition()
        {
            ThreadContext *currentThreadContext =
                Processor.GetCurrentThreadContext();
#if SINGULARITY_KERNEL
            // In Singularity kernel this function is the exit point of a kernel ABI.
            // If the thread is requested to be aborted, we stop it right here
            currentThreadContext->thread.ProcessAbortIfRequested(AbortRequestSource.ABINoGCExit);
#endif
            TakeDormantControl(currentThreadContext);
        }

        [Inline]
        internal static unsafe bool InDormantState(int threadIndex) {
            ThreadContext *threadContext = GetThreadContext(threadIndex);
            return (threadContext == null ||
                    fInDormantState(threadContext->gcStates));
        }

        [Inline]
        internal static unsafe bool InMutatorState(int threadIndex) {
            ThreadContext *threadContext = GetThreadContext(threadIndex);
            return InMutatorState(threadContext);
        }

        [Inline]
        [NoHeapAllocation]
        internal static unsafe bool InMutatorState(ThreadContext *threadContext)
        {
            return (threadContext != null &&
                    fInMutatorState(threadContext->gcStates));
        }

        [Inline]
        internal static unsafe bool HasGCRequest(int threadIndex) {
            ThreadContext *threadContext = GetThreadContext(threadIndex);
            return (threadContext != null &&
                    fHasGCRequest(threadContext->gcStates));
        }

        [Inline]
        internal static unsafe bool UnderGCControl(int threadIndex) {
            ThreadContext *threadContext = GetThreadContext(threadIndex);
            return (threadContext != null &&
                    fUnderGCControl(threadContext->gcStates));
        }

        [Inline]
        internal static unsafe void TakeDormantControl(int threadIndex)
        {
            ThreadContext *threadContext = GetThreadContext(threadIndex);
            TakeDormantControl(ref threadContext->gcStates, threadIndex);
        }

        [Inline]
        internal static unsafe
        void TakeDormantControl(ThreadContext *threadContext)
        {
            TakeDormantControl(ref threadContext->gcStates,
                               threadContext->threadIndex);
        }

        [Inline]
        internal static unsafe
        void TakeDormantControlNoGC(int currentThreadIndex)
        {
            ThreadContext *threadContext =
                GetCurrentThreadContext(currentThreadIndex);
            TakeDormantControlNoGC(ref threadContext->gcStates);
        }

        [Inline]
        internal static unsafe
        void TakeMutatorControl(int currentThreadIndex)
        {
            ThreadContext *threadContext =
                GetCurrentThreadContext(currentThreadIndex);
            TakeMutatorControl(threadContext);
        }

        [Inline]
        internal static unsafe
        void TakeMutatorControlNoGC(int currentThreadIndex)
        {
            ThreadContext *threadContext =
                GetCurrentThreadContext(currentThreadIndex);
            TakeMutatorControlNoGC(threadContext);
        }

        [Inline]
        internal static unsafe
        void TakeMutatorControl(ThreadContext *threadContext)
        {
            TakeMutatorControl(ref threadContext->gcStates,
                               threadContext->threadIndex);
        }

        [Inline]
        internal static unsafe
        void TakeMutatorControlNoGC(ThreadContext *threadContext)
        {
            TakeMutatorControlNoGC(ref threadContext->gcStates,
                                   threadContext->threadIndex);
        }

        internal static unsafe
        void TakeInitialMutatorControl(ThreadContext *threadContext)
        {
            TakeInitialMutatorControl(ref threadContext->gcStates,
                                      threadContext->threadIndex);
        }

        [Inline]
        internal static unsafe
        void TransferMutatorControl(ThreadContext *currentThreadContext)
        {
            TransferMutatorControl(ref currentThreadContext->gcStates,
                                   currentThreadContext->threadIndex);
        }

        [Inline]
        internal static unsafe
        void EnsureMutatorControl(ThreadContext *currentThreadContext)
        {
            EnsureMutatorControl(ref currentThreadContext->gcStates,
                                 currentThreadContext->threadIndex);
        }

        [Inline]
        internal static unsafe
        void EnsureMutatorControlNoGC(ThreadContext *currentThreadContext)
        {
            EnsureMutatorControlNoGC(ref currentThreadContext->gcStates,
                                     currentThreadContext->threadIndex);
        }

        [Inline]
        internal static unsafe
        void EnsureDormantControl(int currentThreadIndex) {
            ThreadContext *threadContext =
                GetCurrentThreadContext(currentThreadIndex);
            if (!fInDormantState(threadContext->gcStates)) {
                TakeDormantControlNoGC(ref threadContext->gcStates);
            }
        }

        [Inline]
        internal static unsafe bool TakeGCControl(int threadIndex) {
            ThreadContext *threadContext = GetThreadContext(threadIndex);
            return (threadContext != null &&
                    TakeGCControl(ref threadContext->gcStates));
        }

        [Inline]
        internal static unsafe void ReleaseGCControl(int threadIndex) {
            ThreadContext *threadContext = GetThreadContext(threadIndex);
            if (threadContext != null) {
                ReleaseGCControl(ref threadContext->gcStates, threadIndex);
            }
        }

        [Inline]
        internal static unsafe void MakeGCRequest(int threadIndex) {
            ThreadContext *threadContext = GetThreadContext(threadIndex);
            if (threadContext != null) {
                MakeGCRequest(ref threadContext->gcStates, threadIndex);
            }
        }

        [Inline]
        internal static unsafe void ClearGCRequest(int threadIndex) {
            ThreadContext *threadContext = GetThreadContext(threadIndex);
            if (threadContext != null) {
                ClearGCRequest(ref threadContext->gcStates, threadIndex);
            }
        }

#else

        private static int[]       gcReadyTable;

        [NoBarriers]
        [PreInitRefCounts]
        internal static void Initialize()
        {
            // gcReadyTable = new int[Thread.maxThreads];
            gcReadyTable = (int[])
                GCs.BootstrapMemory.Allocate(typeof(int[]), Thread.maxThreads);
            for (int i = 0; i < gcReadyTable.Length; i++) {
                gcReadyTable[i] = DormantState;
            }
        }

        // To be used for callbacks into managed space
        [RequiredByBartok]
        [Inline]
        internal static void EntryIntoManagedSpace() {
            int currentThreadIndex = Thread.GetCurrentThreadIndex();
            TakeMutatorControl(currentThreadIndex);
        }

        // To be used for returning from a callback into managed space
        [RequiredByBartok]
        [Inline]
        internal static void ReturnFromManagedSpace() {
            TakeDormantControl(Thread.GetCurrentThreadIndex());
        }

        [RequiredByBartok]
        [Inline]
        internal static void ReturnFromManagedSpaceNoCallerTransition() {
            TakeDormantControl(Thread.GetCurrentThreadIndex());
        }

        [Inline]
        internal static bool InDormantState(int threadIndex) {
            return fInDormantState(gcReadyTable[threadIndex]);
        }

        [Inline]
        internal static bool InMutatorState(int threadIndex) {
            return fInMutatorState(gcReadyTable[threadIndex]);
        }

        [Inline]
        internal static bool HasGCRequest(int threadIndex) {
            return fHasGCRequest(gcReadyTable[threadIndex]);
        }

        [Inline]
        internal static bool UnderGCControl(int threadIndex) {
            return fUnderGCControl(gcReadyTable[threadIndex]);
        }

        [Inline]
        internal static void TakeDormantControl(int currentThreadIndex) {
            TakeDormantControl(ref gcReadyTable[currentThreadIndex],
                               currentThreadIndex);
        }

        [Inline]
        internal static void TakeDormantControlNoGC(int currentThreadIndex) {
            TakeDormantControlNoGC(ref gcReadyTable[currentThreadIndex]);
        }

        [Inline]
        internal static void TakeMutatorControl(int currentThreadIndex) {
            TakeMutatorControl(ref gcReadyTable[currentThreadIndex],
                               currentThreadIndex);
        }

        [Inline]
        internal static void TakeMutatorControlNoGC(int currentThreadIndex) {
            TakeMutatorControlNoGC(ref gcReadyTable[currentThreadIndex],
                                   currentThreadIndex);
        }

        internal static void TakeInitialMutatorControl(int currentThreadIndex)
        {
            TakeInitialMutatorControl(ref gcReadyTable[currentThreadIndex],
                                      currentThreadIndex);
        }

        [Inline]
        internal static bool TakeGCControl(int threadIndex) {
            return TakeGCControl(ref gcReadyTable[threadIndex]);
        }

        [Inline]
        internal static void ReleaseGCControl(int threadIndex) {
            ReleaseGCControl(ref gcReadyTable[threadIndex], threadIndex);
        }

        [Inline]
        internal static void MakeGCRequest(int threadIndex) {
            MakeGCRequest(ref gcReadyTable[threadIndex], threadIndex);
        }

        [Inline]
        internal static void ClearGCRequest(int threadIndex) {
            ClearGCRequest(ref gcReadyTable[threadIndex], threadIndex);
        }

#endif

        #endregion

    }

}
