MSWindowsRuntime.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Исходный код среды исполнения ПВТ-ОО.

    Этот исходный код является частью проекта ПВТ-ОО.

    Copyright © 2021 Малик Разработчик

    Это свободная программа: вы можете перераспространять её и/или
    изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она может быть полезна,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://www.gnu.org/licenses/>.
*/

package platform.dependent;

import platform.independent.filesystem.*;

package final class MSWindowsRuntime(Runtime)
{
    private static final int NORMAL      = 0x0000;
    private static final int STRINGS     = 0x0001;
    private static final int EXECUTABLES = 0x0002;

    private static final long FOLD_SIZE = 0x00400000L;
    private static final long HEAP_SIZE = 0x00800000L;
    private static final long DATA_SIZE = 0x10000000L;

    private static int count;
    private static long[][] fold;

    package static void initialize() {
        protectProgrammeImportRegion();
        long foldPointer = Kernel32.virtualAlloc(0L, FOLD_SIZE, Kernel32.MEM_COMMIT, Kernel32.PAGE_READWRITE);
        fold = (long[][]) initializeInstance(foldPointer, long[][].class, FOLD_SIZE, (int) (FOLD_SIZE - 0x40L >> 3));
        invokeMainConstructor((Runtime) allocateInstanceIn(newHeap(DATA_SIZE, NORMAL), MSWindowsRuntime.class, MSWindowsRuntime.class.instanceSize, -1));
    }

    private static void protectProgrammeImportRegion() {
        long2 importRegion = getProgrammeImportRegion();
        long importRegionBegin = importRegion[0];
        long importRegionEnd = importRegion[1];
        importRegionEnd += -importRegionEnd & 0x0fffL;
        Kernel32.virtualProtect(importRegionBegin, importRegionEnd - importRegionBegin, Kernel32.PAGE_READONLY);
    }

    private static native int getHeapIndexOfFreeSpace(long[] heapRef, int blockLength);

    private static native int getHeapIndexOfBlockPointer(long[] heapRef, long blockPointer);

    private static native long getHeapBlockPointer(long[] heapRef, int blockIndex);

    private static native long2 getProgrammeImportRegion();

    private static long[] newHeap(long dataSize, int heapFlags) {
        long heapSize = dataSize >> 5;
        long heapPointer = Kernel32.virtualAlloc(0L, heapSize, Kernel32.MEM_COMMIT, Kernel32.PAGE_READWRITE);
        if(heapPointer == Kernel32.NULL) return null;
        long dataPointer = Kernel32.virtualAlloc(0L, dataSize, Kernel32.MEM_COMMIT, (heapFlags & EXECUTABLES) == 0 ? Kernel32.PAGE_READWRITE : Kernel32.PAGE_EXECUTE_READWRITE);
        if(dataPointer == Kernel32.NULL) return null;
        int heapLength = (int) (heapSize - 0x40L >> 3);
        long[] result = (long[]) initializeInstance(heapPointer, long[].class, heapSize, heapLength);
        result[heapLength - 2] = dataPointer & -0x1000L | heapFlags & 0x0fff;
        return fold[count++] = result;
    }

    private static Object allocateInstanceIn(long[] heapRef, Class type, long size, int length) {
        int blockLength = (int) (size + (-size & 0xffL) >> 8);
        int blockIndex = getHeapIndexOfFreeSpace(heapRef, blockLength);
        if(blockIndex < 0) return null;
        long prevBlock = blockIndex == 0 ? 0L : heapRef[blockIndex - 1];
        int blockOffset = (int) (prevBlock + (prevBlock >> 32));
        int heapBlocks = heapRef.length - 1;
        int blockCount = (int) heapRef[heapBlocks];
        Object result = initializeInstance((heapRef[heapBlocks - 1] & -0x1000L) + ((long) blockOffset << 8), type, (long) blockLength << 8, length);
        Array.copy(heapRef, blockIndex, heapRef, blockIndex + 1, blockCount - blockIndex);
        heapRef[blockIndex] = ####blockOffset | ^^^^blockLength;
        heapRef[heapBlocks] = blockCount + 1;
        return result;
    }

    private static Object allocateInstanceByFlags(int heapFlags, Class type, long size, int length) {
        for(int index = count; index-- > 0; )
        {
            long[] heapRef = fold[index];
            if(((int) heapRef[heapRef.length - 2] & 0x0fff) == heapFlags)
            {
                Object instance = allocateInstanceIn(heapRef, type, size, length);
                if(instance != null) return instance;
            }
        }
        return null;
    }


    private int fldGCStackLength;
    private long[][] fldGCStackHeaps;
    private long[] fldGCStackPointers;
    private final int fldProcessorNumberOfCores;
    private final Mutex fldGCStackMutex;
    private final Mutex fldHeapMutex;
    private final String fldOSVersion;
    private final FileSystem fldOSFileSystem;
    private final OutOfMemoryError fldErrorNotFreedMemory;
    private final InstantiationError fldErrorNotInstancible;
    private final NoClassDefFoundError fldErrorNotDefinedClass;

    public () {
        int majorVersion = 0;
        int minorVersion = 0;
        int buildNumber = 0;
        try
        {
            KUSER_SHARED_DATA kuser = (KUSER_SHARED_DATA) KUSER_SHARED_DATA.class.newStructAt(0x7ffe0000L);
            majorVersion = kuser.ntMajorVersion;
            minorVersion = kuser.ntMinorVersion;
            buildNumber = kuser.ntBuildNumber;
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        SystemInfo sysinfo = new SystemInfo();
        Kernel32.getSystemInfo(sysinfo.getPointer());
        fldGCStackHeaps = new long[31][];
        fldGCStackPointers = new long[31];
        fldProcessorNumberOfCores = sysinfo.dwNumberOfProcessors;
        fldGCStackMutex = new Mutex();
        fldHeapMutex = new Mutex();
        fldOSVersion = (new StringBuilder() + Int.toUnsignedString(majorVersion) + '.' + Int.toUnsignedString(minorVersion) + '.' + Int.toUnsignedString(buildNumber)).toString();
        fldOSFileSystem = new MSWindowsFileSystem();
        fldErrorNotFreedMemory = new OutOfMemoryError("не хватает памяти для размещения нового объекта");
        fldErrorNotInstancible = new InstantiationError("тип не предназначен для размещения объектов");
        fldErrorNotDefinedClass = new NoClassDefFoundError("тип объекта не определён");
    }

    public void exit(int statusCode) { Kernel32.exitProcess(statusCode); }

    public long freeMemory() {
        long result = 0L;
        boolean multiThreaded = this.multiThreaded;
        Mutex heapmutex = fldHeapMutex;
        if(multiThreaded) heapmutex.lock();
        try
        {
            for(int index = count; index-- > 0; )
            {
                long[] heapRef = fold[index];
                int heapBlocks = heapRef.length - 1;
                int blockIndex = (int) heapRef[heapBlocks] - 1;
                long lastBlock = blockIndex < 0 ? 0L : heapRef[blockIndex];
                int blockOffset = (int) (lastBlock + (lastBlock >> 32));
                result += (long) (heapBlocks - blockOffset + 9) << 8;
            }
        }
        finally
        {
            if(multiThreaded) heapmutex.unlock();
        }
        return result;
    }

    public long totalMemory() {
        long result = 0L;
        boolean multiThreaded = this.multiThreaded;
        Mutex heapmutex = fldHeapMutex;
        if(multiThreaded) heapmutex.lock();
        try
        {
            for(int index = count; index-- > 0; )
            {
                result += (long) (fold[index].length + 8) << 8;
            }
        }
        finally
        {
            if(multiThreaded) heapmutex.unlock();
        }
        return result;
    }

    protected void collectGarbage() {
        for(Mutex heapmutex = fldHeapMutex, int topHeapIndex = 0; topHeapIndex < count; topHeapIndex++)
        {
            long[] topHeapRef = fold[topHeapIndex];
            if(topHeapRef != null) for(int topHeapBlocks = topHeapRef.length - 1, int topBlockIndex = 0; topBlockIndex < (int) topHeapRef[topHeapBlocks]; topBlockIndex++)
            {
                long topBlockPointer = getHeapBlockPointer(topHeapRef, topBlockIndex);
                gcStackCapture(topHeapRef, topBlockPointer);
                try
                {
                    long2 refCounters = refsToInstance(topBlockPointer);
                    label0: if(refCounters == new long2 { 0L, 0L } || refCounters == new long2 { 0L, refsFromInstance(topBlockPointer, topBlockPointer) })
                    {
                        /* Удаляем объект с нулевым количеством ссылок на него или объект, количество ссылок на который равно количеству ссылок из него на него самого */
                        invokeBeforeDestruction(topBlockPointer);
                        releaseRefsInInstance(topBlockPointer);
                        heapmutex.lock();
                        try
                        {
                            int curBlockIndex = getHeapIndexOfBlockPointer(topHeapRef, topBlockPointer);
                            int endBlockIndex = (int) topHeapRef[topHeapBlocks] - 1;
                            int curBlockLength = (int) (topHeapRef[curBlockIndex] >> 32);
                            Array.copy(topHeapRef, curBlockIndex + 1, topHeapRef, curBlockIndex, endBlockIndex - curBlockIndex);
                            topHeapRef[endBlockIndex] = 0L;
                            topHeapRef[topHeapBlocks] = endBlockIndex;
                            modCollectedBytes((long) curBlockLength << 8);
                            if(curBlockIndex <= topBlockIndex) topBlockIndex--;
                        }
                        finally
                        {
                            heapmutex.unlock();
                        }
                    }
                    else if(refCounters[0] == 0L)
                    {
                        /* Удаляем «острова изоляции» (группу объектов, которые ссылаются друг на друга и не имеют других ссылок на себя) */
                        int gcStackLength = fldGCStackLength;
                        long[] gcStackPointers = fldGCStackPointers;
                        for(boolean added = true; added; ) for(added = false, int subHeapIndex = 0; subHeapIndex < count; subHeapIndex++)
                        {
                            long[] subHeapRef = fold[subHeapIndex];
                            if(subHeapRef != null) for(int subHeapBlocks = subHeapRef.length - 1, int subBlockIndex = 0; subBlockIndex < (int) subHeapRef[subHeapBlocks]; subBlockIndex++)
                            {
                                long subBlockPointer = getHeapBlockPointer(subHeapRef, subBlockIndex);
                                boolean pushed = gcStackPush(subHeapRef, subBlockPointer);
                                if(pushed)
                                {
                                    gcStackPointers = fldGCStackPointers;
                                    gcStackLength = fldGCStackLength;
                                }
                                if((refCounters = refsToInstance(subBlockPointer)) == new long2 { 0L, 0L } || refCounters == new long2 { 0L, refsFromInstance(subBlockPointer, subBlockPointer) })
                                {
                                    invokeBeforeDestruction(subBlockPointer);
                                    releaseRefsInInstance(subBlockPointer);
                                    heapmutex.lock();
                                    try
                                    {
                                        int curBlockIndex = getHeapIndexOfBlockPointer(subHeapRef, subBlockPointer);
                                        int endBlockIndex = (int) subHeapRef[subHeapBlocks] - 1;
                                        int curBlockLength = (int) (subHeapRef[curBlockIndex] >> 32);
                                        Array.copy(subHeapRef, curBlockIndex + 1, subHeapRef, curBlockIndex, endBlockIndex - curBlockIndex);
                                        subHeapRef[endBlockIndex] = 0L;
                                        subHeapRef[subHeapBlocks] = endBlockIndex;
                                        modCollectedBytes((long) curBlockLength << 8);
                                        if(curBlockIndex <= subBlockIndex) subBlockIndex--;
                                    }
                                    finally
                                    {
                                        heapmutex.unlock();
                                    }
                                    if(subBlockPointer == topBlockPointer) break label0;
                                    gcStackDelete(subBlockPointer);
                                    gcStackLength = fldGCStackLength;
                                } else
                                {
                                    if(pushed)
                                    {
                                        gcStackDelete(subBlockPointer);
                                        gcStackLength = fldGCStackLength;
                                    }
                                    if(refCounters[0] == 0L) for(int i = gcStackLength; i-- > 0; )
                                    {
                                        if(refsFromInstance(subBlockPointer, gcStackPointers[i]) != 0L && gcStackPush(subHeapRef, subBlockPointer))
                                        {
                                            gcStackPointers = fldGCStackPointers;
                                            gcStackLength = fldGCStackLength;
                                            added = true;
                                            break;
                                        }
                                    }
                                    else for(int i = gcStackLength; i-- > 0; )
                                    {
                                        if(refsFromInstance(subBlockPointer, gcStackPointers[i]) != 0L) break label0;
                                    }
                                }
                            }
                        }
                        for(int i = gcStackLength; i-- > 0; )
                        {
                            long gcStackPointer = gcStackPointers[i];
                            refCounters = refsToInstance(gcStackPointer);
                            if(refCounters[0] != 0L) break label0;
                            long refCounterToInstance = refCounters[1];
                            for(int j = 0; j < gcStackLength; j++)
                            {
                                refCounterToInstance -= refsFromInstance(gcStackPointers[j], gcStackPointer);
                            }
                            if(refCounterToInstance != 0L) break label0;
                        }
                        for(int i = 0; i < gcStackLength; i++)
                        {
                            invokeBeforeDestruction(gcStackPointers[i]);
                        }
                        for(int i = 0; i < gcStackLength; i++)
                        {
                            releaseRefsInInstance(gcStackPointers[i]);
                        }
                        for(long[][] gcStackHeaps = fldGCStackHeaps, int i = 0; i < gcStackLength; i++)
                        {
                            long[] subHeapRef = gcStackHeaps[i];
                            long subBlockPointer = gcStackPointers[i];
                            int subHeapBlocks = subHeapRef.length - 1;
                            heapmutex.lock();
                            try
                            {
                                int curBlockIndex = getHeapIndexOfBlockPointer(subHeapRef, subBlockPointer);
                                int endBlockIndex = (int) subHeapRef[subHeapBlocks] - 1;
                                int curBlockLength = (int) (subHeapRef[curBlockIndex] >> 32);
                                Array.copy(subHeapRef, curBlockIndex + 1, subHeapRef, curBlockIndex, endBlockIndex - curBlockIndex);
                                subHeapRef[endBlockIndex] = 0L;
                                subHeapRef[subHeapBlocks] = endBlockIndex;
                                modCollectedBytes((long) curBlockLength << 8);
                            }
                            finally
                            {
                                heapmutex.unlock();
                            }
                        }
                        topBlockIndex = Int.max(topBlockIndex - gcStackLength, -1);
                    }
                }
                finally
                {
                    gcStackClear();
                }
            }
        }
    }

    protected boolean isProtectedMemory(long beginPointer, long endPointer) {
        if(super.isProtectedMemory(beginPointer, endPointer) || isIntersectRegion(fold, FOLD_SIZE, beginPointer, endPointer)) return true;
        boolean multiThreaded = this.multiThreaded;
        Mutex heapmutex = fldHeapMutex;
        if(multiThreaded) heapmutex.lock();
        try
        {
            for(int index = count; index-- > 0; )
            {
                long[] heapRef = fold[index];
                int heapCapacity = heapRef.length + 8;
                if(isIntersectRegion(heapRef, (long) heapCapacity << 3, beginPointer, endPointer)) return true;
                long dataPointer = heapRef[heapCapacity - 10] & -0x1000L;
                if(isIntersectRegion(dataPointer, dataPointer + ((long) heapCapacity << 8), beginPointer, endPointer)) return true;
            }
        }
        finally
        {
            if(multiThreaded) heapmutex.unlock();
        }
        return false;
    }

    protected Object allocateInstance(Class type, long size, int length, boolean executable) {
        if(type == null)
        {
            throw fldErrorNotDefinedClass;
        }
        if(type.isPrimitive() || type.isAbstract())
        {
            throw fldErrorNotInstancible;
        }
        int heapFlags = executable ? EXECUTABLES : type == String.class || type == char[].class ? STRINGS : NORMAL;
        boolean multiThreaded = this.multiThreaded;
        Mutex heapmutex = fldHeapMutex;
        Object instance = null;
        if(multiThreaded) heapmutex.lock();
        try
        {
            if((instance = allocateInstanceByFlags(heapFlags, type, size, length)) == null)
            {
                long[] heapRef = newHeap(size + (-size & (DATA_SIZE - 1L)), heapFlags);
                if(heapRef != null) instance = allocateInstanceIn(heapRef, type, size, length);
            }
        }
        finally
        {
            if(multiThreaded) heapmutex.unlock();
        }
        if(instance == null)
        {
            throw fldErrorNotFreedMemory;
        }
        return instance;
    }

    protected String intern(String string) {
        if(string == null) return null;
        for(Mutex gcstmutex = fldGCStackMutex, int index = 0; index < count; index++)
        {
            int heapBlocks;
            long[] heapRef = fold[index];
            if(heapRef != null && ((int) heapRef[(heapBlocks = heapRef.length - 1) - 1] & STRINGS) != 0) for(int blockIndex = 0; blockIndex < (int) heapRef[heapBlocks]; blockIndex++)
            {
                long blockPointer = getHeapBlockPointer(heapRef, blockIndex);
                if(blockPointer != 0L)
                {
                    Object instance = null;
                    gcstmutex.lock();
                    try
                    {
                        int gcStackLength = fldGCStackLength;
                        if(gcStackLength > 0 && Array.indexOf(blockPointer, fldGCStackPointers, 0, gcStackLength) >= 0 || getInstanceClass(blockPointer) != String.class) continue;
                        instance = toInstance(blockPointer);
                    }
                    finally
                    {
                        gcstmutex.unlock();
                    }
                    if(instance.equals(string)) return (String) instance;
                }
            }
        }
        return string;
    }

    protected int processorNumberOfCores { read = fldProcessorNumberOfCores }

    protected String lineSeparator { read = "\r\n" }

    protected String operatingSystemName { read = "Microsoft Windows" }

    protected String operatingSystemVersion { read = fldOSVersion }

    protected FileSystem localFileSystem { read = fldOSFileSystem }

    private void gcStackClear() {
        Mutex gcstmutex = fldGCStackMutex;
        gcstmutex.lock();
        try
        {
            fldGCStackLength = 0;
        }
        finally
        {
            gcstmutex.unlock();
        }
    }

    private void gcStackDelete(long blockPointer) {
        Mutex gcstmutex = fldGCStackMutex;
        gcstmutex.lock();
        try
        {
            int length = fldGCStackLength;
            if(length > 0)
            {
                int index = length - 1;
                long[] pointers = fldGCStackPointers;
                if((index = Array.lastIndexOf(blockPointer, pointers, index, 0)) >= 0)
                {
                    int quantity = --length - index;
                    long[][] heaps = fldGCStackHeaps;
                    Array.copy(heaps, index + 1, heaps, index, quantity);
                    Array.copy(pointers, index + 1, pointers, index, quantity);
                    fldGCStackLength = length;
                }
            }
        }
        finally
        {
            gcstmutex.unlock();
        }
    }

    private void gcStackCapture(long[] heapRef, long blockPointer) {
        Mutex gcstmutex = fldGCStackMutex;
        gcstmutex.lock();
        try
        {
            fldGCStackLength = 1;
            fldGCStackHeaps[0] = heapRef;
            fldGCStackPointers[0] = blockPointer;
        }
        finally
        {
            gcstmutex.unlock();
        }
    }

    private boolean gcStackPush(long[] heapRef, long blockPointer) {
        boolean result = false;
        Mutex gcstmutex = fldGCStackMutex;
        gcstmutex.lock();
        try
        {
            int length = fldGCStackLength;
            long[] pointers = fldGCStackPointers;
            if(length <= 0 || Array.indexOf(blockPointer, pointers, 0, length) < 0)
            {
                long[][] heaps = fldGCStackHeaps;
                if(length == heaps.length)
                {
                    int capacity = (length << 1) + 1;
                    Array.copy(heaps, 0, fldGCStackHeaps = heaps = new long[capacity][], 0, length);
                    Array.copy(pointers, 0, fldGCStackPointers = pointers = new long[capacity], 0, length);
                }
                heaps[length] = heapRef;
                pointers[length] = blockPointer;
                fldGCStackLength = length + 1;
                result = true;
            }
        }
        finally
        {
            gcstmutex.unlock();
        }
        return result;
    }
}