/*
Исходный код среды исполнения ПВТ-ОО.
Этот исходный код является частью проекта ПВТ-ОО.
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;
}
}