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

// ISA_ is the prefix used by Singularity for the system architecture
#if ARM || ISA_ARM
    [StructLayout(LayoutKind.Sequential)]
    internal struct CompressedFrameDescriptor /* : CompressedFrameDescriptorTemplate */
    {
        private UIntPtr mask;

        internal bool IsCompressed()
        {
            return ((this.mask & (UIntPtr) Constants.CompactMask) != 0);
        }

        internal bool IsFramePointerOmitted()
        {
            return ((this.mask & (UIntPtr) Constants.CompactOmitFPMask) != 0);
        }

        internal bool HasTransitionRecord()
        {
            return ((this.mask & (UIntPtr) Constants.CompactTransitionRecordMask) != 0);
        }

        internal uint StackArgSize()
        {
            return ((this.mask >> Constants.CompactArgMaskStart) & Constants.CompactArgMask);
        }

        internal UIntPtr ArgumentMaskNoFP()
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return (this.mask >> 5);
        }

        internal UIntPtr CalleeSaveValueMaskNoFP()
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return ((this.mask >> Constants.CompactCalleeSaveUseStartNoFP) & (UIntPtr) Constants.CompactCalleeSaveUseMaskNoFP);
        }

        internal UIntPtr CalleeSaveMaskNoFP()
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return ((this.mask >> 8) & (UIntPtr) 0xff);
        }

        internal int FrameSizeNoFP()
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return unchecked((int) (this.mask & 0x1f));
        }

        internal int InBetweenSlotsAboveNoFP()
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return Constants.InbetweenSlotsAboveNoFP;
        }

        internal int InBetweenSlotsBelowNoFP()
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return Constants.InbetweenSlotsBelowNoFP;
        }

        internal UIntPtr ArgumentMaskWithFP()
        {
            return (this.mask >> Constants.CompactStackBitMaskStartFP);
        }

        internal UIntPtr CalleeSaveValueMaskWithFP()
        {
            return ((this.mask >> Constants.CompactCalleeSaveUseStartFP) & (UIntPtr) Constants.CompactCalleeSaveUseMaskFP);
        }

        internal UIntPtr CalleeSaveMaskWithFP()
        {
            return ((this.mask >> Constants.CompactCalleeSaveStartFP) & (UIntPtr) Constants.CompactCalleeSaveMaskFP);
        }

        internal int InBetweenSlotsAboveWithFP()
        {
            return Constants.InbetweenSlotsAboveFP;
        }

        internal int InBetweenSlotsBelowWithFP()
        {
            return Constants.InbetweenSlotsBelowFP;
        }

        internal unsafe OverflowFrameDescriptor *OverflowDescriptor()
        {
            return (OverflowFrameDescriptor *) this.mask;
        }

        internal unsafe
        bool IsFramePointerOmitted(OverflowFrameDescriptor *overflow)
        {
            return ((overflow->mask & (UIntPtr) Constants.FullOmitFPMask) != 0);
        }

        internal unsafe
        bool HasTransitionRecord(OverflowFrameDescriptor *overflow)
        {
            return ((overflow->mask & (UIntPtr) Constants.FullTransitionRecordMask) != 0);
        }

        internal unsafe
        UIntPtr CalleeSaveValueMaskNoFP(OverflowFrameDescriptor *overflow)
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return this.CalleeSaveValueMaskNoFP();
        }

        internal unsafe
        UIntPtr CalleeSaveMaskNoFP(OverflowFrameDescriptor *overflow)
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return this.CalleeSaveMaskNoFP();
        }

        internal unsafe
        bool HasPinnedPointersNoFP(OverflowFrameDescriptor *overflow)
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return ((overflow->mask & (UIntPtr) 0x1) != 0);
        }

        internal unsafe int FrameSizeNoFP(OverflowFrameDescriptor *overflow)
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return unchecked((int) (overflow->mask >> 4));
        }

        internal unsafe uint EntrySizeNoFP(OverflowFrameDescriptor *overflow)
        {
            // Current bridge doesn't support omitting frame pointer.
            VTable.Assert(false, "Omit FP not supported.");
            return unchecked((uint) ((overflow->mask >> 1) & (UIntPtr) 0x7));
        }

        internal unsafe
        UIntPtr CalleeSaveValueMaskWithFP(OverflowFrameDescriptor *overflow)
        {
            return ((overflow->mask >> Constants.FullCalleeSaveUseStartFP) & (UIntPtr) Constants.FullCalleeSaveUseMaskFP);
        }

        internal unsafe
        UIntPtr CalleeSaveMaskWithFP(OverflowFrameDescriptor *overflow)
        {
            return ((overflow->mask >> Constants.FullCalleeSaveStartFP) & (UIntPtr) Constants.FullCalleeSaveMaskFP);
        }

        internal unsafe
        bool HasPinnedPointersWithFP(OverflowFrameDescriptor *overflow)
        {
            return (((overflow->mask >> Constants.FullPinnedPosFP) & (UIntPtr) 0x1) != 0);
        }

        internal unsafe uint EntrySizeWithFP(OverflowFrameDescriptor *overflow)
        {
            return unchecked((uint) ((overflow->mask >> Constants.FullRecordSizePosFP) & (UIntPtr) Constants.FullRecordMask));
        }

        internal static unsafe UIntPtr NextCallSite(bool omitFP, UIntPtr *fp, out UIntPtr *sp)
        {
            if (omitFP) {
                VTable.Assert(false, "ARM doesn't support FPO");
                sp = (UIntPtr*)UIntPtr.Zero;
            } else {
                sp = (UIntPtr*)*(fp - 2);
                return *(fp - 1);
            }
            return UIntPtr.Zero;
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct OverflowFrameDescriptor {
        internal UIntPtr mask;
        internal int variableData;
    }  
#endif

}
