/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package platform.dependent.mswindows.runtime;
import avt.security.*;
import platform.dependent.mswindows.kernel.*;
import platform.independent.filesystem.*;
public final class Win32Runtime(Runtime)
{
/*<fold вычисленные точкой входа размеры областей тагированного стака>*/
public static final long TAGGED_STACK_DATA_AREA_SIZE;
public static final long TAGGED_STACK_CONTEXT_AREA_SIZE;
/*</fold>*/
/*<fold атрибуты куч>*/
private static final int NORMAL = 0;
private static final int EXECUTABLE = 1;
/*</fold>*/
/*<fold адресное пространство>*/
private static final long PAGE_SIZE = 0x0000000000001000L;
private static final long ADDRESS_SPACE_CAPACITY = 0x0000800000000000L;
/*</fold>*/
/*<fold каталог куч>*/
private static long heapsAligned;
private static Heap64[] heapsCatalogue;
/*</fold>*/
/*<fold контекст безопасности вызывающего метода>*/
private static CallerSecurityContext securityContext;
/*</fold>*/
public static void initialize() {
protectProgrammeImportRegion();
final long allocationSize = Heap64.MIN_ALLOC_SIZE;
long heapsLength = ADDRESS_SPACE_CAPACITY / (allocationSize + getHeapSize(allocationSize));
long heapsSize = heapsLength * long.class.instanceSize + Heap64[].class.instanceSize;
long heapsPointer = Kernel.virtualAlloc(0, heapsAligned = heapsSize + (-heapsSize & PAGE_SIZE - 1), Kernel.MEM_COMMIT, Kernel.PAGE_READWRITE);
(heapsCatalogue = (Heap64[]) initializeInstance(heapsPointer, Heap64[].class, Heap64[].class.instanceSize, (int) heapsLength, null)).length = 0;
long runtimeSize = class.instanceSize;
long runtimePointer = newHeap(Heap64.getAllocationSize(runtimeSize), NORMAL).allocate(runtimeSize);
construct((Runtime) initializeInstance(runtimePointer, class, runtimeSize, -1, null));
securityContext = new CallerSecurityContext();
}
public static void finalize() {
destruct(securityContext);
}
package static CallerSecurityContext getSecurityContext() { return securityContext; }
private static void protectProgrammeImportRegion() {
long2 importRegionPointers = getProgrammeImportRegionPointers();
long importRegionBeginPointer = importRegionPointers[0];
long importRegionEndPointer = importRegionPointers[1];
Kernel.virtualProtect(importRegionBeginPointer, importRegionEndPointer - importRegionBeginPointer + (-importRegionEndPointer & PAGE_SIZE - 1), Kernel.PAGE_READONLY);
}
private static int4 getOperatingSystemVersion() {
try
{
KUSER_SHARED_DATA kuser = (KUSER_SHARED_DATA) KUSER_SHARED_DATA.class.newStructAt(0x7ffe0000L);
return new int4 { kuser.ntMajorVersion, kuser.ntMinorVersion, kuser.ntBuildNumber, 0 };
}
catch(Exception exception)
{
throw exception instanceof RuntimeException ? (RuntimeException) exception : new RuntimeException(exception.message, exception);
}
}
private static long getHeapSize(long allocationSize) {
long heapAligned = (long) Heap64.class.instanceSize;
long mmapAligned = (long) Heap64.getMemoryMapLength(allocationSize) * int4.class.instanceSize + int4[].class.instanceSize;
heapAligned += -heapAligned & Heap64.BLOCK_SIZE - 1;
mmapAligned += -mmapAligned & Heap64.BLOCK_SIZE - 1;
long infoSize = heapAligned + mmapAligned;
return infoSize + (-infoSize & PAGE_SIZE - 1);
}
private static native long getThreadEntryPoint();
private static native long2 getProgrammeImportRegionPointers();
private static Heap64 newHeap(long allocationSize, int attributes) {
boolean isExecutable = (attributes & EXECUTABLE) != 0;
int mmapLength = Heap64.getMemoryMapLength(allocationSize);
long heapSize = (long) Heap64.class.instanceSize;
long mmapSize = (long) mmapLength * int4.class.instanceSize + int4[].class.instanceSize;
long heapAligned = heapSize + (-heapSize & Heap64.BLOCK_SIZE - 1);
long mmapAligned = mmapSize + (-mmapSize & Heap64.BLOCK_SIZE - 1);
long infoSize = heapAligned + mmapAligned;
infoSize += -infoSize & PAGE_SIZE - 1;
long heapPointer = Kernel.virtualAlloc(0, isExecutable ? infoSize : infoSize + allocationSize, Kernel.MEM_COMMIT, Kernel.PAGE_READWRITE);
long dataPointer = !isExecutable ? heapPointer + infoSize : Kernel.virtualAlloc(0, allocationSize, Kernel.MEM_COMMIT, Kernel.PAGE_EXECUTE_READWRITE);
if(heapPointer == 0)
{
if(isExecutable && dataPointer != 0) Kernel.virtualFree(dataPointer, 0, Kernel.MEM_RELEASE);
return null;
}
if(dataPointer == 0)
{
Kernel.virtualFree(heapPointer, 0, Kernel.MEM_RELEASE);
return null;
}
long mmapPointer = heapPointer + heapAligned;
int4[] memoryMap = (int4[]) initializeInstance(mmapPointer, int4[].class, int4[].class.instanceSize, mmapLength, securityContext);
Heap64 result = (Heap64) initializeInstance(heapPointer, Heap64.class, heapSize, -1, securityContext);
constructInstance(result, securityContext);
result.initialize(dataPointer, attributes, memoryMap);
int length = heapsCatalogue.length;
heapsCatalogue.length = length + 1;
return heapsCatalogue[length] = result;
}
private int[] fldGarbageCollectorIndices;
private long[] fldGarbageCollectorPointers;
private final int fldProcessorNumberOfCores;
private final long fldOperatingSystemAppMinPointer;
private final long fldOperatingSystemAppMaxPointer;
private final CriticalSection fldHeapOperation;
private final String fldOperatingSystemVersion;
private final Services fldOperatingSystemServices;
private final OutOfMemoryError fldErrorNotFreedMemory;
private final InstantiationError fldErrorNotInstancible;
private final NoClassDefFoundError fldErrorNotDefinedType;
public () {
int4 osversion;
final Package lang = avt.lang.package;
SystemInfo sysinfo = new SystemInfo();
Kernel.getSystemInfo(sysinfo.getPointer());
fldGarbageCollectorIndices = new int[0x0fff];
fldGarbageCollectorPointers = new long[0x0fff];
fldProcessorNumberOfCores = sysinfo.dwNumberOfProcessors;
fldOperatingSystemAppMinPointer = sysinfo.lpMinimumApplicationAddress;
fldOperatingSystemAppMaxPointer = sysinfo.lpMaximumApplicationAddress;
fldHeapOperation = new CriticalSection();
fldOperatingSystemVersion = (new StringBuilder() +
Int.toUnsignedString((osversion = getOperatingSystemVersion())[0]) + '.' +
Int.toUnsignedString(osversion[1]) + '.' +
Int.toUnsignedString(osversion[2])
).toString();
fldOperatingSystemServices = new Services();
fldErrorNotFreedMemory = new OutOfMemoryError(lang.getResourceString("!machine-error.out-of-memory"));
fldErrorNotInstancible = new InstantiationError(lang.getResourceString("!reflective-error.instantiation"));
fldErrorNotDefinedType = new NoClassDefFoundError(lang.getResourceString("!reflective-error.no-class-def-found"));
}
public void exit(int exitCode) {
destruct(securityContext);
Kernel.exitProcess(exitCode);
}
public long freeMemory() {
long result = 0;
boolean multiThreaded = this.multiThreaded;
CriticalSection operation = fldHeapOperation;
if(multiThreaded) operation.lock();
try
{
for(int index = heapsCatalogue.length; index-- > 0; )
{
result += heapsCatalogue[index].freeMemory();
}
} finally
{
if(multiThreaded) operation.unlock();
}
return result;
}
public long totalMemory() {
long result = 0;
boolean multiThreaded = this.multiThreaded;
CriticalSection operation = fldHeapOperation;
if(multiThreaded) operation.lock();
try
{
for(int index = heapsCatalogue.length; index-- > 0; )
{
result += heapsCatalogue[index].allocationSize;
}
} finally
{
if(multiThreaded) operation.unlock();
}
return result;
}
protected void collectGarbage() {
for(CriticalSection operation = fldHeapOperation, int topCtlgIdx = 0; topCtlgIdx < heapsCatalogue.length; topCtlgIdx++)
{
if(isTerminated()) return;
Heap64 topHeapRef = heapsCatalogue[topCtlgIdx];
if(topHeapRef == null) break;
for(int topHeapIdx = 0; topHeapIdx < topHeapRef.length; topHeapIdx++)
{
if(isTerminated()) return;
long topInstPtr = (long) topHeapRef[topHeapIdx];
long2 refCounters = refsToInstance(topInstPtr, securityContext);
label0: if(refCounters == new long2 { 0, 0 } || refCounters == new long2 { 0, refsFromInstance(topInstPtr, topInstPtr, securityContext) })
{
/* Удаляем объект с нулевым количеством ссылок на него или объект, количество ссылок на который равно количеству ссылок из него на него самого */
invokeBeforeDestruction(topInstPtr, securityContext);
releaseRefsInInstance(topInstPtr, securityContext);
operation.lock();
try
{
modCollectedBytes(topHeapRef.free(topInstPtr));
} finally
{
operation.unlock();
}
topHeapIdx--;
}
else if(refCounters[0] == 0)
{
int length = 1;
int[] indices = fldGarbageCollectorIndices;
long[] pointers = fldGarbageCollectorPointers;
indices[0] = topCtlgIdx;
pointers[0] = topInstPtr;
for(boolean added = true; added; ) for(added = false, int subCtlgIdx = 0; subCtlgIdx < heapsCatalogue.length; subCtlgIdx++)
{
if(isTerminated()) return;
Heap64 subHeapRef = heapsCatalogue[subCtlgIdx];
if(subHeapRef == null) break;
for(int subHeapIdx = 0; subHeapIdx < subHeapRef.length; subHeapIdx++)
{
if(isTerminated()) return;
long subInstPtr = (long) subHeapRef[subHeapIdx];
if(
(refCounters = refsToInstance(subInstPtr, securityContext)) == new long2 { 0, 0 } ||
refCounters == new long2 { 0, refsFromInstance(subInstPtr, subInstPtr, securityContext) }
)
{
/* Удаляем объект с нулевым количеством ссылок на него или объект, количество ссылок на который равно количеству ссылок из него на него самого */
invokeBeforeDestruction(subInstPtr, securityContext);
releaseRefsInInstance(subInstPtr, securityContext);
operation.lock();
try
{
modCollectedBytes(subHeapRef.free(subInstPtr));
} finally
{
operation.unlock();
}
subHeapIdx--;
}
else if(refCounters[0] == 0)
{
for(int pti = length; pti-- > 0; )
{
if(isTerminated()) return;
if(refsFromInstance(subInstPtr, pointers[pti], securityContext) > 0)
{
int status = garbageCollectorAddInstance(subCtlgIdx, subInstPtr, indices, pointers, length);
if(status < 0)
{
break label0;
}
if(status > 0)
{
if(status == 1)
{
indices = fldGarbageCollectorIndices;
pointers = fldGarbageCollectorPointers;
}
length++;
added = true;
break;
}
}
}
}
else
{
for(int pti = length; pti-- > 0; )
{
if(isTerminated()) return;
if(refsFromInstance(subInstPtr, pointers[pti], securityContext) > 0) break label0;
}
}
}
}
for(int pti = length; pti-- > 0; )
{
if(isTerminated()) return;
long subInstPtr = pointers[pti];
if((refCounters = refsToInstance(subInstPtr, securityContext))[0] != 0) break label0;
long refCounter = refCounters[1];
for(int ptj = length; ptj-- > 0; )
{
if(isTerminated()) return;
refCounter -= refsFromInstance(pointers[ptj], subInstPtr, securityContext);
}
if(refCounter != 0) break label0;
}
/* Удаляем «острова изоляции» (группу объектов, которые ссылаются друг на друга и не имеют других ссылок на себя) */
for(int pti = 0; pti < length; pti++)
{
if(isTerminated()) return;
invokeBeforeDestruction(pointers[pti], securityContext);
}
for(int pti = 0; pti < length; pti++)
{
if(isTerminated()) return;
releaseRefsInInstance(pointers[pti], securityContext);
}
int delta = 0;
for(int pti = 0; pti < length; pti++)
{
if(isTerminated()) return;
int subCtlgIdx = indices[pti];
long subInstPtr = pointers[pti];
Heap64 subHeapRef = heapsCatalogue[subCtlgIdx];
if(subCtlgIdx == topCtlgIdx) delta++;
operation.lock();
try
{
modCollectedBytes(subHeapRef.free(subInstPtr));
} finally
{
operation.unlock();
}
}
if((topHeapIdx -= delta) < -1) topHeapIdx = -1;
}
}
}
}
protected void throwOutOfMemoryError() {
throw fldErrorNotFreedMemory;
}
protected void yieldThread() {
Kernel.switchToThread();
}
protected void startThreadId(long threadId) {
if(threadId < Int.MIN_VALUE || threadId > Int.MAX_VALUE)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "threadId" }));
}
long threadHandle = Kernel.openThread(Kernel.THREAD_SUSPEND_RESUME, false, (int) threadId);
if(threadHandle == Kernel.INVALID_HANDLE_VALUE)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "threadId" }));
}
try
{
Kernel.resumeThread(threadHandle);
} finally
{
Kernel.closeHandle(threadHandle);
}
}
protected void setThreadIdPriority(long threadId, int priority) {
if(threadId < Int.MIN_VALUE || threadId > Int.MAX_VALUE)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "threadId" }));
}
long threadHandle = Kernel.openThread(Kernel.THREAD_SET_LIMITED_INFORMATION, false, (int) threadId);
if(threadHandle == Kernel.INVALID_HANDLE_VALUE)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "threadId" }));
}
try
{
switch(priority)
{
default:
priority = priority >= Thread.MAX_PRIORITY ? Kernel.THREAD_PRIORITY_TIME_CRITICAL : Kernel.THREAD_PRIORITY_IDLE;
break;
case Thread.LOW_PRIORITY - 1:
priority = Kernel.THREAD_PRIORITY_LOWEST;
break;
case Thread.LOW_PRIORITY - 0:
priority = Kernel.THREAD_PRIORITY_BELOW_NORMAL;
break;
case Thread.NORM_PRIORITY - 1:
case Thread.NORM_PRIORITY + 0:
case Thread.NORM_PRIORITY + 1:
priority = Kernel.THREAD_PRIORITY_NORMAL;
break;
case Thread.HIGH_PRIORITY + 0:
priority = Kernel.THREAD_PRIORITY_ABOVE_NORMAL;
break;
case Thread.HIGH_PRIORITY + 1:
priority = Kernel.THREAD_PRIORITY_HIGHEST;
break;
}
Kernel.setThreadPriority(threadHandle, priority);
} finally
{
Kernel.closeHandle(threadHandle);
}
}
protected boolean isAliveThreadId(long threadId) {
if(threadId < Int.MIN_VALUE || threadId > Int.MAX_VALUE)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "threadId" }));
}
long threadHandle = Kernel.openThread(Kernel.THREAD_QUERY_LIMITED_INFORMATION, false, (int) threadId);
if(threadHandle == Kernel.INVALID_HANDLE_VALUE)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "threadId" }));
}
try
{
int2 result = Kernel.getExitCodeThread(threadHandle);
return result[0] != 0 && result[1] == Kernel.STILL_ACTIVE;
} finally
{
Kernel.closeHandle(threadHandle);
}
}
protected boolean isCanonicalPointer(long pointer) {
return super.isCanonicalPointer(pointer) && pointer >= fldOperatingSystemAppMinPointer && pointer <= fldOperatingSystemAppMaxPointer;
}
protected boolean isProtectedMemory(long2 regionPointers) {
if(super.isProtectedMemory(regionPointers) || isIntersectRegions(toMemoryRegionPointers(heapsCatalogue, heapsAligned), regionPointers)) return true;
boolean multiThreaded = this.multiThreaded;
CriticalSection operation = fldHeapOperation;
if(multiThreaded) operation.lock();
try
{
for(int index = heapsCatalogue.length; index-- > 0; )
{
Heap64 heap = heapsCatalogue[index];
long allocationSize = heap.allocationSize;
if(
isIntersectRegions(toMemoryRegionPointers(heap, getHeapSize(allocationSize)), regionPointers) ||
isIntersectRegions(toMemoryRegionPointers(heap.allocationPointer, allocationSize), regionPointers)
) return true;
}
} finally
{
if(multiThreaded) operation.unlock();
}
return false;
}
protected int getThreadIdPriority(long threadId) {
if(threadId < Int.MIN_VALUE || threadId > Int.MAX_VALUE)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "threadId" }));
}
long threadHandle = Kernel.openThread(Kernel.THREAD_QUERY_LIMITED_INFORMATION, false, (int) threadId);
if(threadHandle == Kernel.INVALID_HANDLE_VALUE)
{
throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "threadId" }));
}
try
{
switch(Kernel.getThreadPriority(threadHandle))
{
case Kernel.THREAD_PRIORITY_IDLE:
return Thread.MIN_PRIORITY;
case Kernel.THREAD_PRIORITY_LOWEST:
return Thread.LOW_PRIORITY - 1;
case Kernel.THREAD_PRIORITY_BELOW_NORMAL:
return Thread.LOW_PRIORITY - 0;
default:
return Thread.NORM_PRIORITY + 0;
case Kernel.THREAD_PRIORITY_ABOVE_NORMAL:
return Thread.HIGH_PRIORITY + 0;
case Kernel.THREAD_PRIORITY_HIGHEST:
return Thread.HIGH_PRIORITY + 1;
case Kernel.THREAD_PRIORITY_TIME_CRITICAL:
return Thread.MAX_PRIORITY;
}
} finally
{
Kernel.closeHandle(threadHandle);
}
}
protected int activeThreadsCount() {
int result = 0;
int processId = Kernel.getCurrentProcessId();
long snapshotHandle = Kernel.createToolHelp32Snapshot(Kernel.TH32CS_SNAPTHREAD, 0);
try
{
ThreadEntry32 threadInfoObject = new ThreadEntry32() { dwSize = ThreadEntry32.class.structSize };
long threadInfoPointer = threadInfoObject.getPointer();
if(Kernel.thread32First(snapshotHandle, threadInfoPointer)) do
{
if(threadInfoObject.th32OwnerProcessID == processId) result++;
} while(Kernel.thread32Next(snapshotHandle, threadInfoPointer));
} finally
{
Kernel.closeHandle(snapshotHandle);
}
return result;
}
protected long newThreadId(Thread reference) {
long result = Kernel.createThread(0, 0x1000L, getThreadEntryPoint(), toPointer(reference), Kernel.CREATE_SUSPENDED)[1];
addOtherRefInInstance(reference, securityContext);
return result;
}
protected long currentThreadId() {
return (long) Kernel.getCurrentThreadId();
}
protected long[] activeThreadsIds() {
int length = 0;
int processId = Kernel.getCurrentProcessId();
long[] result = new long[0x0fi];
long snapshotHandle = Kernel.createToolHelp32Snapshot(Kernel.TH32CS_SNAPTHREAD, 0);
try
{
ThreadEntry32 threadInfoObject = new ThreadEntry32() { dwSize = ThreadEntry32.class.structSize };
long threadInfoPointer = threadInfoObject.getPointer();
if(Kernel.thread32First(snapshotHandle, threadInfoPointer)) do
{
if(threadInfoObject.th32OwnerProcessID == processId)
{
if(length == result.length)
{
Array.copy(result, 0, result = new long[length << 1 | 1], 0, length);
}
result[length++] = threadInfoObject.th32ThreadID;
}
} while(Kernel.thread32Next(snapshotHandle, threadInfoPointer));
} finally
{
Kernel.closeHandle(snapshotHandle);
}
if(length != result.length)
{
Array.copy(result, 0, result = new long[length], 0, length);
}
return result;
}
protected platform.dependent.Event newEvent(long threadId) { return new Win32Event(threadId); }
protected platform.dependent.Mutex newMutex() { return new CriticalSection(); }
protected platform.dependent.Monitor newMonitor() { return new Monitor(); }
protected Object allocateInstance(Class type, long size, int length, boolean executable) {
if(type == null)
{
throw fldErrorNotDefinedType;
}
if(type.isPrimitive() || type.isAbstract())
{
throw fldErrorNotInstancible;
}
int attributes = executable ? EXECUTABLE : NORMAL;
Object instance = null;
label0:
{
boolean multiThreaded = this.multiThreaded;
CriticalSection operation = fldHeapOperation;
if(multiThreaded) operation.lock();
try
{
for(int limit = heapsCatalogue.length, int index = 0; index < limit; index++)
{
Heap64 heap = heapsCatalogue[index];
if(heap.attributes != attributes) continue;
long pointer = heap.allocateStart(size);
if(pointer != 0)
{
instance = initializeInstance(pointer, type, size + (-size & Heap64.BLOCK_SIZE - 1), length, securityContext);
heap.allocateFinish();
break label0;
}
}
Heap64 heap = newHeap(Heap64.getAllocationSize(size), attributes);
if(heap != null)
{
long pointer = heap.allocateStart(size);
if(pointer != 0)
{
instance = initializeInstance(pointer, type, size + (-size & Heap64.BLOCK_SIZE - 1), length, securityContext);
heap.allocateFinish();
}
}
} finally
{
if(multiThreaded) operation.unlock();
}
}
if(instance == null)
{
throw fldErrorNotFreedMemory;
}
return instance;
}
protected int processorNumberOfCores { read = fldProcessorNumberOfCores }
protected platform.dependent.TimeBase timeBase { read = fldOperatingSystemServices }
protected FileSystem localFileSystem { read = fldOperatingSystemServices }
protected String lineSeparator { read = "\r\n" }
protected String operatingSystemName { read = "Microsoft Windows" }
protected String operatingSystemVersion { read = fldOperatingSystemVersion }
protected String entryPointTypeCanonicalName { read = "platform.dependent.mswindows.EntryPoint" }
protected platform.dependent.ProcessEnvironment currentProcessEnvironment { read = fldOperatingSystemServices }
private int garbageCollectorAddInstance(int index, long pointer, int[] indices, long[] pointers, int length) {
if(Array.indexOf(pointer, pointers, 0, length) < 0)
{
if(length == pointers.length)
{
int capacity = length << 1 | 1;
if(capacity < 0) return -1;
Array.copy(pointers, 0, fldGarbageCollectorPointers = pointers = new long[capacity], 0, length);
Array.copy(indices, 0, fldGarbageCollectorIndices = indices = new int[capacity], 0, length);
pointers[length] = pointer;
indices[length] = index;
return 1;
}
pointers[length] = pointer;
indices[length] = index;
return 2;
}
return 0;
}
}