//
// 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;

    internal unsafe class StaticData
    {
        [RequiredByBartok]
        private static int sectionCount;
        [RequiredByBartok]
        private static UIntPtr **dataSectionEnd; // unmanaged uint**[]
        [RequiredByBartok]
        private static UIntPtr **dataSectionBase; // unmanaged uint**[]
        [RequiredByBartok]
        private static UIntPtr **roDataSectionEnd; // unmanaged uint**[]
        [RequiredByBartok]
        private static UIntPtr **roDataSectionBase; // unmanaged uint**[]
        [RequiredByBartok]
        private static uint **staticDataPointerBitMap; // unmanaged uint*[]

        [PreInitRefCounts]
#if !SINGULARITY                // Needed before Bartok runtime is initialized
        [NoStackLinkCheck]
#endif
        internal static void Initialize() {
            for (int section = 0; section < sectionCount; section++) {
                UIntPtr startAddr = (UIntPtr) dataSectionBase[section];
                startAddr = PageTable.PageAlign(startAddr);
                UIntPtr size = (UIntPtr) dataSectionEnd[section] - startAddr;
                size = PageTable.PagePad(size);
                PageManager.SetStaticDataPages(startAddr, size);
            }
            for (int section = 0; section < sectionCount; section++) {
                UIntPtr startAddr = (UIntPtr) roDataSectionBase[section];
                startAddr = PageTable.PageAlign(startAddr);
                UIntPtr size = (UIntPtr) roDataSectionEnd[section]-startAddr;
                size = PageTable.PagePad(size);
                PageManager.SetStaticDataPages(startAddr, size);
            }
        }

        internal static
        void ScanStaticData(DirectReferenceVisitor referenceVisitor)
        {
            Finalizer.VisitBootstrapData(referenceVisitor);
            for (int section = 0; section < sectionCount; section++) {
                int size = (int)
                    (*(dataSectionEnd+section)-*(dataSectionBase+section));
                int iters = (size + 31) / 32;
                UIntPtr *ptr = *(dataSectionBase+section);
                uint *pointerBitmap = *(staticDataPointerBitMap+section);
                for (int i = 0; i < iters; i++) {
                    uint mask = *pointerBitmap++;
                    if (mask != 0) {
                        for (int j = 0; j < 32; j++) {
                            if ((mask & 1) != 0 && *ptr != UIntPtr.Zero) {
                                referenceVisitor.Visit(ptr);
                            }
                            ptr++;
                            mask >>= 1;
                        }
                    } else {
                        ptr += 32;
                    }
                }
            }
        }

        internal static
        uint ScanStaticPointerData(NonNullReferenceVisitor referenceVisitor)
        {
            uint totalSize = 0;
            for (int section = 0; section < sectionCount; section++) {
                uint size = (uint)(*(dataSectionEnd+section)-
                    *(dataSectionBase+section));
                totalSize += size;
                UIntPtr *ptr = *(dataSectionBase+section);
                uint *pointerBitmap = *(staticDataPointerBitMap+section);
                uint iters = (size + 31) / 32;
                for (uint i = 0; i < iters; i++) {
                    uint mask = *pointerBitmap++;
                    if (mask != 0) {
                        for (int j = 0; j < 32; j++) {
                            if ((mask & 1) != 0) {
                                referenceVisitor.Visit(ptr);
                            }
                            ptr++;
                            mask >>= 1;
                        }
                    } else {
                        ptr += 32;
                    }
                }
            }

            for (int section = 0; section < sectionCount; section++) {
                uint size = (uint)(*(roDataSectionEnd+section)-
                    *(roDataSectionBase+section));
                totalSize += size;
            }

            return totalSize*(uint)UIntPtr.Size;
        }
    }

}
