//
// 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.       */
/*******************************************************************/


// The header part of an object is split into a PreHeader and a
// PostHeader component.  The PreHeader component is the part of the
// object residing in memory preceding the pointer to the object and
// the PostHeader component is the part at and after the pointer to
// the object.
//
// The StageControl.ObjectHeaderKind option controls which kind of
// header to use.  However, this option provides only basic control.
// Fields can be added to the headers outside the control of this
// StageControl option by using the mixin mechanism.
//
// The "Default" header kind has a MultiUseWord in the PreHeader and a
// VTable in the PostHeader.  The "PostRC" header kind has a
// MultiUseWord in the PreHeader and a refState followed by a VTable
// in the PostHeader.

namespace Microsoft.Bartok.Runtime {

    using Microsoft.Bartok.Options;

    using System;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using Interlocked = System.Threading.Interlocked;

    [RequiredByBartok]
    internal struct PreHeader
    {
        [Intrinsic]
        internal static int Size;
    }

    [RequiredByBartok]
#if SINGULARITY
    [AccessedByRuntime("Accessed from halexn.cpp")]
#endif
    internal struct PostHeader
    {
        [Intrinsic]
        internal static int Size;
    }

    [MixinConditional("ObjectHeaderDefault")]
    [MixinConditional("ObjectHeaderPostRC")]
    [Mixin(typeof(PreHeader))]
    [RequiredByBartok]
    internal struct PreHeaderDefault /* : PreHeader */
    {
        internal MultiUseWord muw;
    }

    [MixinConditional("ObjectHeaderDefault")]
    [Mixin(typeof(PostHeader))]
    [RequiredByBartok]
    internal struct PostHeaderDefault /* : PostHeader */
    {

#if SINGULARITY
        [AccessedByRuntime("accessed from halexn.cpp")]
#else
        [RequiredByBartok]
#endif
        [NoBarriers]
        internal VTable vtableObject;
    }

    [RequiredByBartok]
    [MixinConditional("ObjectHeaderPostRC")]
    [Mixin(typeof(PostHeader))]
    [StructLayout(LayoutKind.Sequential)]
    internal struct PostHeaderRC /* : PostHeader */
    {
        [CompilerInitField(2)]
        internal uint refState;

#if !SINGULARITY
        [RequiredByBartok]
#endif
        [NoBarriers]
        internal VTable vtableObject;

    }

    // This class does not add any fields, nor should it ever be
    // referenced by any other code.  Its sole purpose is to add
    // implementations of the get_vtable, set_vtable, and
    // get_VTableFieldAddr methods to all objects.
    [MixinConditional("ObjectHeaderDefault")]
    [Mixin(typeof(System.Object))]
    internal class ObjectPostVTable
    {
#if SINGULARITY
        [AccessedByRuntime("Accessed from halexn.cpp")]
#endif
        [RequiredByBartok]
        internal new PostHeaderDefault postHeader;

        internal new VTable vtable {
            [Inline]
            get { return this.postHeader.vtableObject; }
            [Inline]
            set { this.postHeader.vtableObject = value; }
        }

        internal unsafe new UIntPtr* VTableFieldAddr {
            [ManualRefCounts]
            [NoBarriers]
            get { return Magic.toPointer(ref this.postHeader.vtableObject); }
        }

    }

    // This class does not add any fields, nor should it ever be
    // referenced by any other code.  Its sole purpose is to add
    // implementations of the get_vtable, set_vtable, and
    // get_VTableFieldAddr methods to all objects.
    [MixinConditional("ObjectHeaderPostRC")]
    [Mixin(typeof(System.Object))]
    internal class ObjectPostVTableRC
    {
        [RequiredByBartok]
        internal new PostHeaderRC postHeader;

        internal new VTable vtable {
            [Inline]
            get { return this.postHeader.vtableObject; }
            [Inline]
            set { this.postHeader.vtableObject = value; }
        }

        internal unsafe new UIntPtr* VTableFieldAddr {
            [ManualRefCounts]
            [NoBarriers]
            get { return Magic.toPointer(ref this.postHeader.vtableObject); }
        }

    }

    // This class does not add any fields, nor should it ever be
    // referenced by any other code.  Its sole purpose is to declare
    // that all objects have get_muw, set_muw, and compareExchangeMUW
    // methods when the object header includes a MultiUseWord field.
    [MixinConditional("ObjectHeaderDefault")]
    [MixinConditional("ObjectHeaderPostRC")]
    [Mixin(typeof(System.Object))]
    internal class ObjectMUW {

        internal extern MultiUseWord muw {
            [Inline]
            get;
            [Inline]
            set;
        }

        [Inline]
        internal extern UIntPtr CompareExchangeMUW(UIntPtr newValue,
                                                   UIntPtr oldValue);

    }

    // This class does not add any fields, nor should it ever be
    // referenced by any other code.  Its sole purpose is to add
    // implementations of the get_muw, set_muw, and compareExchangeMUW
    // methods to all objects when they have a MultiUseWord field.
    [MixinConditional("ObjectHeaderDefault")]
    [MixinConditional("ObjectHeaderPostRC")]
    [Mixin(typeof(ObjectMUW))]
    internal class ObjectPreMUW : ObjectMUW {

        internal new PreHeaderDefault preHeader;

        internal new MultiUseWord muw {
            [Inline]
            get { return this.preHeader.muw; }
            [Inline]
            set { this.preHeader.muw = value; }
        }

        [Inline]
        internal new UIntPtr CompareExchangeMUW(UIntPtr newValue,
                                                UIntPtr oldValue)
        {
            return Interlocked.CompareExchange(ref this.preHeader.muw.value,
                                               newValue, oldValue);
        }

    }

}
