//
// 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 Microsoft.Bartok.Runtime;
    using Microsoft.Bartok.Options;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Threading;

    internal unsafe class BrooksBarrierTest: UniversalWriteBarrier {
        internal static BrooksBarrierTest instance;
        
        internal static bool allowFastPath;
        
        [NoBarriers]
        internal static new void Initialize()
        {
            BrooksBarrierTest.instance =
                (BrooksBarrierTest)
                BootstrapMemory.Allocate(typeof(BrooksBarrierTest));
        }

        [RequiredByBartok]
        [MixinConditional("BrooksBarrierTest")]
        [Mixin(typeof(PreHeader))]
        internal struct BrooksPreHeader {
            internal MultiUseWord muw;
            [SelfPoint]
            internal Object forward;
        }
        
        [MixinConditional("BrooksBarrierTest")]
        [Mixin(typeof(Object))]
        internal class BrooksObject: System.Object {
            internal new BrooksPreHeader preHeader;
        }
        
        internal static BrooksObject MixinObject(Object o) {
            return (BrooksObject)o;
        }
        
        [NoBarriers]
        internal static Object Forward(Object o)
        {
            Object result=MixinObject(o).preHeader.forward;
            VTable.Assert(result == o);
            return result;
        }
        
        [NoBarriers]
        internal static Object ForwardNullable(Object o)
        {
            if (o==null) {
                return null;
            } else {
                return Forward(o);
            }
        }
        
        [NoBarriers]
        [Inline]
        protected override Object ForwardImpl(Object o,int mask)
        {
            if ((mask&BarrierMask.PathSpec.AllowFast)!=0) {
                return o;
            } else {
                if ((mask&BarrierMask.Forward.Nullable)!=0 && o == null) {
                    return null;
                } else {
                    return Forward(o);
                }
            }
        }
        
        [ForceInline]
        [NoBarriers]
        protected override bool AllowFastPathImpl()
        {
            return allowFastPath;
        }
        
        [ForceInline]
        [NoBarriers]
        protected override void InitObjectImpl(Object o, VTable vtable)
        {
            MyInitObject(o, vtable);
        }

        [ForceInline]
        [NoBarriers]
        internal static new void BootstrapInitObjectImpl(Object o,
                                                         VTable vtable)
        {
            MyInitObject(o, vtable);
        }

        [ForceInline]
        [NoBarriers]
        private static void MyInitObject(Object o, VTable vtable)
        {
            MixinObject(o).preHeader.forward = o;
            o.vtable = vtable;
        }
        
        [ForceInline]
        [NoBarriers]
        protected override Object AtomicCompareAndSwapImpl(ref Object loc,
                                                           Object newVal,
                                                           Object comp,
                                                           int mask)
        {
            for (;;) {
                Object oldVal = loc;
                Object commitVal;
                if (oldVal == comp ||
                    ForwardNullable(oldVal) == ForwardNullable(comp)) {
                    commitVal = newVal;
                } else {
                    // still CAS but only to get a memory barrier
                    commitVal = oldVal;
                }
                if (Interlocked.CompareExchange(ref loc,
                                                commitVal, oldVal)
                    == oldVal) {
                    return oldVal;
                }
            }
        }
        
        [ForceInline]
        [NoBarriers]
        protected override bool EqImpl(Object a,Object b,int mask)
        {
            if ((mask&BarrierMask.PathSpec.AllowFast)!=0) {
                return a == b;
            } else {
                return a == b || ForwardNullable(a) == ForwardNullable(b);
            }
        }
    }
}

