/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.lang;
import avt.lang.array.*;
import platform.dependent.*;
import platform.independent.osservices.*;
public class Runtime(Object)
{
static final long INSTANCE_ALIGN = 0x40;
static final long ARRAY_HEADER_SIZE = 0x40;
private static int count = 0; /* все кучи: общее количество куч */
private static long collectedCounter = 0; /* счётчики: собранное сборщиком мусора количество байт */
private static long allocatedBytes = 0; /* счётчики: занятое количество байт */
private static long totalBytes = 0; /* счётчики: всего выделено байт */
private static long[] pointers; /* недостижимые объекты: указатели на объекты */
private static long[] counters; /* недостижимые объекты: счётчики ссылок на объекты */
private static long[] sizes; /* каталоги куч: размеры объектов */
private static Heap[] heaps; /* все кучи: объекты куч */
private static Heap[][] catalogues; /* каталоги куч: объекты каталогов */
private static Mutex memoryOperation;
private static OutOfMemoryError errorOutOfMemory;
private static InstantiationError errorInstantiation;
private static Runtime instance;
private static final long CATALOGUE_HEADER_SIZE = 2 * ARRAY_HEADER_SIZE;
private static final long MAX_ALLOCATED_BYTES_HEAP = 1L << 38;
private static final long MAX_ALLOCATED_BYTES_CATALOGUE = 1L << 37;
public static Runtime getInstance() { return instance; }
protected static void finalize() {
if(Thread.callerTypeTrace() != instance.getClass()) return;
instance.beforeDestruction();
}
protected static boolean initialize(long servicesPtr, Class servicesType) {
if(instance != null || servicesPtr == 0 || servicesType == null || servicesType.isAbstract() || !PlatformServices.class.isAssignableFrom(servicesType)) return false;
Object instance = initInstance(servicesPtr, servicesType, servicesType.instanceSize, -1);
instance.defaultConstructor();
if(!initHeap()) return false;
initErrors();
instance.afterConstruction();
return true;
}
protected static boolean isIntersectRegions(long2 region0, long2 region1) { return Long2.max(region0, region1)[0] < Long2.min(region0, region1)[1]; }
package static void throwOutOfMemoryError() {
throw errorOutOfMemory;
}
/* размещение инстанций */
package static Object allocateInstance(Class instanceType, long instanceSize, int arrayLength) {
if(allocatedBytes + (instanceSize += -instanceSize & (INSTANCE_ALIGN - 1)) > MAX_ALLOCATED_BYTES_HEAP)
{
throw errorOutOfMemory;
}
if(instanceType == null || instanceType.isPrimitive() || instanceType.isAbstract())
{
throw errorInstantiation;
}
int cindex = indexOfSize(instanceSize);
if(cindex < 0)
{
throw errorOutOfMemory;
}
Object result;
boolean multiThreaded = instance.fldMultiThreaded;
if(multiThreaded) memoryOperation.lock();
try
{
Heap[] heaps = catalogues[cindex];
if(heaps == null && (heaps = createCatalogue(cindex)) == null)
{
throw errorOutOfMemory;
}
int hindex = getActiveHeapIndex(heaps);
Heap heap = hindex < heaps.length ? heaps[hindex] : createHeap(cindex);
if(heap == null)
{
throw errorOutOfMemory;
}
result = initInstance(heap.getNextInstancePointer(), instanceType, instanceSize, arrayLength);
heap.captureInstancePointer();
allocatedBytes += heap.objectSize;
if(heap.isFull()) modActiveHeapIndex(heaps);
} finally
{
if(multiThreaded) memoryOperation.unlock();
}
return result;
}
package static Object allocateStruct(Class instanceType, long instanceSize, long structDataPtr) {
if(allocatedBytes + (instanceSize += -instanceSize & (INSTANCE_ALIGN - 1)) > MAX_ALLOCATED_BYTES_HEAP)
{
throw errorOutOfMemory;
}
if(instanceType == null || instanceType.isPrimitive() || instanceType.isAbstract())
{
throw errorInstantiation;
}
int cindex = indexOfSize(instanceSize);
if(cindex < 0)
{
throw errorOutOfMemory;
}
Object result;
boolean multiThreaded = instance.fldMultiThreaded;
if(multiThreaded) memoryOperation.lock();
try
{
Heap[] heaps = catalogues[cindex];
if(heaps == null && (heaps = createCatalogue(cindex)) == null)
{
throw errorOutOfMemory;
}
int hindex = getActiveHeapIndex(heaps);
Heap heap = hindex < heaps.length ? heaps[hindex] : createHeap(cindex);
if(heap == null)
{
throw errorOutOfMemory;
}
result = initStruct(heap.getNextInstancePointer(), instanceType, instanceSize, structDataPtr);
heap.captureInstancePointer();
allocatedBytes += heap.objectSize;
if(heap.isFull()) modActiveHeapIndex(heaps);
} finally
{
if(multiThreaded) memoryOperation.unlock();
}
return result;
}
package static Object allocateArray(Class instanceType, long instanceSize, int arrayLength, long arrayDataPtr, Struct arrayParentStruct) {
if(allocatedBytes + (instanceSize += -instanceSize & (INSTANCE_ALIGN - 1)) > MAX_ALLOCATED_BYTES_HEAP)
{
throw errorOutOfMemory;
}
if(instanceType == null || instanceType.isPrimitive() || instanceType.isAbstract())
{
throw errorInstantiation;
}
int cindex = indexOfSize(instanceSize);
if(cindex < 0)
{
throw errorOutOfMemory;
}
Object result;
boolean multiThreaded = instance.fldMultiThreaded;
if(multiThreaded) memoryOperation.lock();
try
{
Heap[] heaps = catalogues[cindex];
if(heaps == null && (heaps = createCatalogue(cindex)) == null)
{
throw errorOutOfMemory;
}
int hindex = getActiveHeapIndex(heaps);
Heap heap = hindex < heaps.length ? heaps[hindex] : createHeap(cindex);
if(heap == null)
{
throw errorOutOfMemory;
}
result = initArray(heap.getNextInstancePointer(), instanceType, instanceSize, arrayLength, arrayDataPtr, arrayParentStruct);
heap.captureInstancePointer();
allocatedBytes += heap.objectSize;
if(heap.isFull()) modActiveHeapIndex(heaps);
} finally
{
if(multiThreaded) memoryOperation.unlock();
}
return result;
}
static native long toPointer(Object instanceRef);
static native Object toInstance(long instancePtr);
static native Object initInstance(long instancePtr, Class instanceType, long instanceSize, int arrayLength);
static native Object initStruct(long instancePtr, Class instanceType, long instanceSize, long structDataPtr);
static native Object initArray(long instancePtr, Class instanceType, long instanceSize, int arrayLength, long arrayDataPtr, Struct arrayParentStruct);
/* сбор мусора */
static void collectGarbage() {
boolean unstable;
GarbageCollectorThread thread = instance.fldGCThread;
for(int hindex = 0; hindex < count; hindex++)
{
if(thread != null && thread.terminated) return;
Heap heap = heaps[hindex];
heap.initForGC();
for(int ilength = heap.length, int iindex = 0; iindex < ilength; iindex++)
{
if(thread != null && thread.terminated) return;
long instancePtr = heap[iindex];
if(refsToInstance(instancePtr)[0] != 0) heap.makeAttainedInstancePointer(instancePtr);
}
}
do for(unstable = false, int hindex = 0; hindex < count; hindex++)
{
if(thread != null && thread.terminated) return;
Heap heap = heaps[hindex];
if(heap.length <= 0) heap.initForGC();
int attained;
for(int iindex = heap.visited; iindex < (attained = heap.attained); iindex++)
{
if(thread != null && thread.terminated) return;
for(long instancePtr = heap[iindex], int tlength = getInstanceRefsCount(instancePtr), int tindex = -1; tindex < tlength; tindex++)
{
if(thread != null && thread.terminated) return;
long targetPtr = getInstanceRefAtIndex(instancePtr, tindex);
Heap anot = heap.isOwnInstancePointer(targetPtr) ? heap : heapOf(targetPtr);
if(anot == null) continue;
if(anot.length <= 0) anot.initForGC();
anot.makeAttainedInstancePointer(targetPtr);
unstable = true;
}
}
heap.visited = attained;
} while(unstable);
int plength = 0;
int hlength = count;
for(int hindex = 0; hindex < hlength; hindex++)
{
if(thread != null && thread.terminated) return;
Heap heap = heaps[hindex];
plength += heap.length - heap.attained;
}
if(!ensurePointersCapacity(plength))
{
throw errorOutOfMemory;
}
for(plength = 0, pointers.length = pointers.capacity, long previousPtr = Long.MIN_VALUE, int hindex = 0; hindex < hlength; hindex++)
{
if(thread != null && thread.terminated) return;
Heap heap = heaps[hindex];
for(int ilength = heap.length, int iindex = heap.attained; iindex < ilength; iindex++)
{
if(thread != null && thread.terminated) return;
long instancePtr = heap[iindex];
if(previousPtr >= instancePtr) break;
pointers[plength++] = previousPtr = instancePtr;
}
heap.finForGC();
}
for(long refCount, pointers.length = plength, Array.fill(counters, 0, plength, 0); ; )
{
unstable = false;
for(int pindex = 0; pindex < plength; pindex++)
{
if(thread != null && thread.terminated) return;
if(counters[pindex] < 0) continue;
for(long instancePtr = pointers[pindex], int tlength = getInstanceRefsCount(instancePtr), int tindex = -1; tindex < tlength; tindex++)
{
if(thread != null && thread.terminated) return;
int aindex = indexOfPointer(getInstanceRefAtIndex(instancePtr, tindex));
if(aindex >= 0 && (refCount = counters[aindex]) >= 0) counters[aindex] = refCount + 1;
}
}
for(int pindex = 0; pindex < plength; pindex++)
{
if(thread != null && thread.terminated) return;
if((refCount = counters[pindex]) < 0 || refsToInstance(pointers[pindex]) == new long2 { 0, refCount }) continue;
counters[pindex] = -1;
unstable = true;
}
if(!unstable) break;
for(int pindex = 0; pindex < plength; pindex++)
{
if(thread != null && thread.terminated) return;
if(counters[pindex] > 0) counters[pindex] = 0;
}
}
for(int pindex = 0; pindex < plength; pindex++)
{
if(thread != null && thread.terminated) return;
if(counters[pindex] >= 0) invokeBeforeDestruction(pointers[pindex]);
}
for(int pindex = 0; pindex < plength; pindex++)
{
if(thread != null && thread.terminated) return;
if(counters[pindex] >= 0) deallocateInstance(pointers[pindex]);
}
}
private static void deallocateInstance(long instancePtr) {
Heap heap = heapOf(instancePtr);
if(heap == null) return;
finInstance(instancePtr);
int cindex = heap.catalogueIndex;
int hindex = heap.heapIndex;
boolean multiThreaded = instance.fldMultiThreaded;
if(multiThreaded) memoryOperation.lock();
try
{
Heap[] heaps = catalogues[cindex];
heap.releaseInstancePointer(instancePtr);
long objectSize = heap.objectSize;
collectedCounter += objectSize;
allocatedBytes -= objectSize;
if(getActiveHeapIndex(heaps) > hindex) setActiveHeapIndex(heaps, hindex);
} finally
{
if(multiThreaded) memoryOperation.unlock();
}
}
private static void invokeBeforeDestruction(long instancePtr) {
Object instance = toInstance(instancePtr);
if(instance.getClass().isArray()) return;
try
{
instance.beforeDestruction();
} catch(Throwable exception) { }
}
private static native void finInstance(long instancePtr);
private static native int getInstanceRefsCount(long instancePtr);
private static native long getInstanceRefAtIndex(long instancePtr, int index);
private static native long2 refsToInstance(long instancePtr);
/* инициализация кучи */
private static boolean initHeap() {
/* расчёт размеров */
final int sizesLength = 62;
final int cataloguesLength = sizesLength;
final long sizesUnalignedSize = ((long) sizesLength << 3) + ARRAY_HEADER_SIZE;
final long cataloguesUnalignedSize = ((long) cataloguesLength << 3) + ARRAY_HEADER_SIZE;
final long pointersSize = MemoryRegion.PAGE_SIZE >> 1;
final long countersSize = pointersSize;
final long sizesSize = sizesUnalignedSize + (-sizesUnalignedSize & (INSTANCE_ALIGN - 1));
final long heapsSize = MemoryRegion.PAGE_SIZE;
final long cataloguesSize = sizesSize;
/* выделение памяти под массивы */
PlatformServices services = PlatformServices.getInstance();
long2 region = services.allocateRegion(new long2 { 0, pointersSize + countersSize }, MemoryRegion.READABLE | MemoryRegion.WRITEABLE);
if(region == 0) return false;
long pointersPtr = (long) region;
long countersPtr = pointersPtr + pointersSize;
region = services.allocateRegion(new long2 { 0, sizesSize + cataloguesSize }, MemoryRegion.READABLE | MemoryRegion.WRITEABLE);
if(region == 0) return false;
long sizesPtr = (long) region;
long cataloguesPtr = sizesPtr + sizesSize;
region = services.allocateRegion(new long2 { 0, heapsSize }, MemoryRegion.READABLE | MemoryRegion.WRITEABLE);
if(region == 0) return false;
long heapsPtr = (long) region;
/* инициализация массивов */
pointers = (long[]) initInstance(pointersPtr, long[].class, pointersSize, (int) (pointersSize - ARRAY_HEADER_SIZE >> 3));
counters = (long[]) initInstance(countersPtr, long[].class, countersSize, (int) (countersSize - ARRAY_HEADER_SIZE >> 3));
sizes = (long[]) initInstance(sizesPtr, long[].class, sizesUnalignedSize, sizesLength);
heaps = (Heap[]) initInstance(heapsPtr, Heap[].class, heapsSize, (int) (heapsSize - ARRAY_HEADER_SIZE >> 3));
catalogues = (Heap[][]) initInstance(cataloguesPtr, Heap[][].class, cataloguesUnalignedSize, cataloguesLength);
/* заполнение массивов начальными данными */
for(int index = 0; index < 4; index++) sizes[index] = 64L * (index + 1);
for(int index = 5; index < sizesLength; index += 2) sizes[index] = 1L << (index >> 1) + 7;
for(int index = 4; index < sizesLength; index += 2)
{
long size = (long) ((1L << (index >> 1) + 6) * 0x1.6a09e667f3bcc908p+0R);
sizes[index] = size + (-size & (INSTANCE_ALIGN - 1));
}
/* создание нескольких куч */
for(int index = 0; index < 4; index++) if(createCatalogue(index) == null || createHeap(index) == null) return false;
return true;
}
/* инициализация объектов ошибок */
private static void initErrors() {
/* создание необходимых объектов */
memoryOperation = PlatformServices.getInstance().newMutex();
errorOutOfMemory = new OutOfMemoryError();
errorInstantiation = new InstantiationError();
/* инициализация строк */
String.initialize();
errorOutOfMemory.message = package.getResourceString("!machine-error.out-of-memory");
errorInstantiation.message = package.getResourceString("!reflective-error.instantiation");
}
/* недостижимые объекты */
private static boolean ensurePointersCapacity(int minCapacity) {
long[] oldPointersRef = pointers;
int oldPointersCapacity = oldPointersRef.capacity;
if(minCapacity < oldPointersCapacity) return true;
long[] oldCountersRef = counters;
long oldPointersPtr = toPointer(oldPointersRef);
long oldCountersPtr = toPointer(oldCountersRef);
long oldPointersSize = ((long) oldPointersCapacity << 3) + ARRAY_HEADER_SIZE;
long oldCountersSize = oldPointersSize;
long newPointersSize = ((long) minCapacity << 3) + ARRAY_HEADER_SIZE;
long newCountersSize = newPointersSize += -newPointersSize & ((MemoryRegion.PAGE_SIZE >> 1) - 1L);
PlatformServices services = PlatformServices.getInstance();
long2 region = services.allocateRegion(new long2 { 0, newPointersSize + newCountersSize }, MemoryRegion.READABLE | MemoryRegion.WRITEABLE);
if(region == 0) return false;
long newPointersPtr = (long) region;
long newCountersPtr = newPointersPtr + newPointersSize;
pointers = (long[]) initInstance(newPointersPtr, long[].class, newPointersSize, (int) (newPointersSize - ARRAY_HEADER_SIZE >> 3));
counters = (long[]) initInstance(newCountersPtr, long[].class, newCountersSize, (int) (newCountersSize - ARRAY_HEADER_SIZE >> 3));
finInstance(oldPointersPtr);
finInstance(oldCountersPtr);
oldPointersRef = null;
oldCountersRef = null;
services.deallocateRegion(new long2 { oldPointersPtr, oldPointersSize + oldCountersSize }, MemoryRegion.NO_ACCESS);
return true;
}
private static int indexOfPointer(long instancePtr) {
for(int bidx = 0, int eidx = pointers.length - 1; bidx <= eidx; )
{
int midx = bidx + eidx >>> 1;
long currentPtr = pointers[midx];
if(instancePtr == currentPtr) return midx;
if(instancePtr < currentPtr)
{
eidx = midx - 1;
continue;
}
bidx = midx + 1;
}
return -1;
}
/* все кучи */
private static boolean expandHeaps() {
Heap[] oldRef = heaps;
long oldPtr = toPointer(oldRef);
long oldLength = oldRef.capacity;
long oldSize = (oldLength << 3) + ARRAY_HEADER_SIZE;
long newSize = oldSize << 1;
PlatformServices services = PlatformServices.getInstance();
long2 region = services.allocateRegion(new long2 { 0, newSize }, MemoryRegion.READABLE | MemoryRegion.WRITEABLE);
if(region == 0) return false;
long newPtr = (long) region;
Heap[] newRef = (Heap[]) initInstance(newPtr, Heap[].class, newSize, (int) (newSize - ARRAY_HEADER_SIZE >> 3));
copy(oldPtr + ARRAY_HEADER_SIZE, newPtr + ARRAY_HEADER_SIZE, oldLength);
heaps = newRef;
finInstance(oldPtr);
oldRef = null;
services.deallocateRegion(new long2 { oldPtr, oldSize }, MemoryRegion.NO_ACCESS);
return true;
}
private static Heap heapOf(long instancePtr) {
for(int bidx = 0, int eidx = count - 1; bidx <= eidx; )
{
int midx = bidx + eidx >>> 1;
Heap heap = heaps[midx];
long2 bnd = heap.regionBounds;
if(instancePtr < bnd[0])
{
eidx = midx - 1;
continue;
}
if(instancePtr < bnd[1]) return heap;
bidx = midx + 1;
}
return null;
}
/* каталоги куч */
private static void modActiveHeapIndex(Heap[] catalogue) {
int index = getActiveHeapIndex(catalogue) + 1;
for(int length = catalogue.length; index < length; index++) if(!catalogue[index].isFull()) break;
setActiveHeapIndex(catalogue, index);
}
private static native void setActiveHeapIndex(Heap[] catalogue, int newActiveHeapIndex);
private static native int getActiveHeapIndex(Heap[] catalogue);
private static int indexOfSize(long instanceSize) {
for(int bidx = 0, int eidx = sizes.length - 1; bidx <= eidx; )
{
int midx = bidx + eidx >>> 1;
if(instanceSize > sizes[midx])
{
bidx = midx + 1;
continue;
}
int pidx = midx - 1;
if(pidx < 0 || instanceSize > sizes[pidx]) return midx;
eidx = pidx;
}
return -1;
}
private static Heap[] expandCatalogue(int index) {
Heap[] oldRef = catalogues[index];
long oldPtr = toPointer(oldRef);
long oldLength = oldRef.capacity;
long oldSize = (oldLength << 3) + CATALOGUE_HEADER_SIZE;
long newSize = oldSize << 1;
PlatformServices services = PlatformServices.getInstance();
long2 region = services.allocateRegion(new long2 { 0, newSize }, MemoryRegion.READABLE | MemoryRegion.WRITEABLE);
if(region == 0) return null;
long newPtr = (long) region;
Heap[] newRef = (Heap[]) initArray(newPtr, Heap[].class, newSize, (int) (newSize - CATALOGUE_HEADER_SIZE >> 3), newPtr + CATALOGUE_HEADER_SIZE, null);
copy(oldPtr + CATALOGUE_HEADER_SIZE, newPtr + CATALOGUE_HEADER_SIZE, oldLength);
setActiveHeapIndex(newRef, getActiveHeapIndex(oldRef));
newRef.length = oldRef.length;
catalogues[index] = newRef;
finInstance(oldPtr);
oldRef = null;
services.deallocateRegion(new long2 { oldPtr, oldSize }, MemoryRegion.NO_ACCESS);
return newRef;
}
private static Heap[] createCatalogue(int index) {
/*
Начальная ёмкость каталога куч —
в зависимости от размера объекта:
+---------+----------+-----------+
| Индекс | | Начальная |
| размера | Размер | ёмкость, |
| в sizes | объекта | в КБ |
+---------+----------+-----------+
| ≤ 19 | ≤ 64 КБ | 64 |
| 20 | 90,56 КБ | 48 |
| 21 | 128 КБ | 32 |
| 22 | 181,1 КБ | 24 |
| 23 | 256 КБ | 16 |
| 24 | 362,1 КБ | 12 |
| 25 | 512 КБ | 8 |
| 26 | 724,1 КБ | 8 |
| ≥ 27 | ≥ 1 МБ | 4 |
+---------+----------+-----------+
*/
final long KB = 1L << 10;
long catalogueSize = 64 * KB;
if(index > 19) switch(index)
{
case 20:
{
catalogueSize = 48 * KB;
break;
}
case 21:
{
catalogueSize = 32 * KB;
break;
}
case 22:
{
catalogueSize = 24 * KB;
break;
}
case 23:
{
catalogueSize = 16 * KB;
break;
}
case 24:
{
catalogueSize = 12 * KB;
break;
}
case 25:
case 26:
{
catalogueSize = 8 * KB;
break;
}
default:
{
catalogueSize = 4 * KB;
}
}
long2 region = PlatformServices.getInstance().allocateRegion(new long2 { 0, catalogueSize }, MemoryRegion.READABLE | MemoryRegion.WRITEABLE);
if(region == 0) return null;
long cataloguePtr = (long) region;
Heap[] result = (Heap[]) initArray(cataloguePtr, Heap[].class, catalogueSize, (int) (catalogueSize - CATALOGUE_HEADER_SIZE >> 3), cataloguePtr + CATALOGUE_HEADER_SIZE, null);
result.length = 0;
catalogues[index] = result;
return result;
}
private static Heap createHeap(int index) {
int maxHeaps;
int maxObjects;
long objectSize = sizes[index];
if(index > 45)
{
maxHeaps = 1;
maxObjects = (int) (MAX_ALLOCATED_BYTES_CATALOGUE / objectSize);
} else
{
maxHeaps = (int) (MAX_ALLOCATED_BYTES_CATALOGUE / (objectSize << 8));
maxObjects = 256;
}
Heap[] catalogue = catalogues[index];
int length = catalogue.length;
int capacity = catalogue.capacity;
if(length >= (index <= 19 || maxHeaps <= capacity ? maxHeaps : capacity) || length >= capacity && (catalogue = expandCatalogue(index)) == null) return null;
PlatformServices services = PlatformServices.getInstance();
long addedBytes = objectSize * maxObjects;
long2 heapBounds = services.allocateRegion(new long2 { 0, addedBytes }, MemoryRegion.READABLE | MemoryRegion.WRITEABLE);
if(heapBounds == 0) return null;
long heapPtr;
long2 heapRegion = 0;
if((length & 0x3f) > 0)
{
heapPtr = toPointer(catalogue[length - 1]) + Heap.INSTANCE_SIZE;
} else
{
/*
Количество памяти,
выделяемой под кучи за один раз —
в зависимости от размера объекта:
+---------+----------+------------+
| Индекс | | Количество |
| размера | Размер | памяти, |
| в sizes | объекта | в КБ |
+---------+----------+------------+
| ≤ 33 | ≤ 8 МБ | 64 |
| 34 | 11,31 МБ | 48 |
| 35 | 16 МБ | 32 |
| 36 | 22,63 МБ | 24 |
| 37 | 32 МБ | 16 |
| 38 | 45,25 МБ | 12 |
| 39 | 64 МБ | 8 |
| 40 | 90,51 МБ | 8 |
| ≥ 41 | ≥ 128 МБ | 4 |
+---------+----------+------------+
*/
final long KB = 1L << 10;
long heapsSize = 64 * KB;
if(index > 33) switch(index)
{
case 34:
{
heapsSize = 48 * KB;
break;
}
case 35:
{
heapsSize = 32 * KB;
break;
}
case 36:
{
heapsSize = 24 * KB;
break;
}
case 37:
{
heapsSize = 16 * KB;
break;
}
case 38:
{
heapsSize = 12 * KB;
break;
}
case 39:
case 40:
{
heapsSize = 8 * KB;
break;
}
default:
{
heapsSize = 4 * KB;
}
}
heapRegion = services.allocateRegion(new long2 { 0, heapsSize }, MemoryRegion.READABLE | MemoryRegion.WRITEABLE);
if(heapRegion == 0)
{
services.deallocateRegion(heapBounds, MemoryRegion.NO_ACCESS);
return null;
}
heapPtr = (long) heapRegion;
}
int position = count;
if(position >= heaps.capacity && !expandHeaps())
{
if(heapRegion != 0) services.deallocateRegion(heapRegion, MemoryRegion.NO_ACCESS);
services.deallocateRegion(heapBounds, MemoryRegion.NO_ACCESS);
return null;
}
int eidx = position - 1;
long heapStart = (long) heapBounds;
if(eidx >= 0 && heapStart < heaps[eidx].regionPointer)
{
int bidx = 0;
do
{
int midx = bidx + eidx >>> 1;
if(heapStart >= heaps[midx].regionPointer)
{
bidx = midx + 1;
continue;
}
int pidx = midx - 1;
if(pidx < 0 || heapStart > heaps[pidx].regionPointer)
{
Array.copy(heaps, midx, heaps, midx + 1, position - midx);
position = midx;
break;
}
eidx = pidx;
} while(bidx <= eidx);
}
Heap result = (Heap) initInstance(heapPtr, Heap.class, Heap.INSTANCE_SIZE, -1);
result.defaultConstructor();
result.afterConstruction();
result.init(index, length, heapStart, objectSize, maxObjects);
catalogue.length = length + 1;
catalogue[length] = result;
heaps[position] = result;
count++;
totalBytes += addedBytes;
return result;
}
/* вспомогательные методы */
private static native void copy(long srcPtr, long dstPtr, long length);
/* регионы памяти */
private static native long2 getCodeMemoryRegionPointers();
private static native long2 getDataMemoryRegionPointers();
private static long2 getObjectMemoryRegionPointers(Object obj) {
long ptr = toPointer(obj);
return new long2 { ptr, ptr + obj.getClass().instanceSize };
}
private static long2 getArrayMemoryRegionPointers(MutableMeasureable array) {
long ptr = toPointer(array);
return new long2 { ptr, ptr + ((long) array.capacity << 3) + ARRAY_HEADER_SIZE };
}
private static long2 getCatalogueMemoryRegionPointers(Heap[] array) {
long ptr = toPointer(array);
return new long2 { ptr, ptr + ((long) array.capacity << 3) + CATALOGUE_HEADER_SIZE };
}
/* инстанционные члены */
private boolean fldMultiThreaded;
private Mutex fldSystemOperation;
private Object fldGCMonitor;
private GarbageCollectorThread fldGCThread;
protected () {
if(instance != null)
{
throw new SecurityException(package.getResourceString("security.runtime.construct"));
}
instance = this;
}
public void exit(int exitCode) {
throw new SecurityException(package.getResourceString("security.runtime.exit"));
}
public final void gc() {
synchronized with(fldGCMonitor)
{
notify();
}
}
public final long freeMemory() { return totalBytes - allocatedBytes; }
public final long totalMemory() { return totalBytes; }
public final long collectedBytes() { return collectedCounter; }
protected void afterConstruction() {
fldSystemOperation = PlatformServices.getInstance().newMutex();
Thread.initialize();
with((Thread) (fldGCThread = new GarbageCollectorThread(fldGCMonitor = new Object())))
{
priority = MIN_PRIORITY;
name = "GC";
start();
}
}
protected void beforeDestruction() {
GarbageCollectorThread thread = fldGCThread;
if(thread != null) thread.terminate();
}
protected void nowMultiThreaded() { }
protected boolean isCanonicalPointer(long ptr) { return ptr >= 0xffff800000000000L && ptr <= 0x00007fffffffffffL; }
protected boolean isProtectedMemory(long2 regionBounds) {
if(
isIntersectRegions(regionBounds, getCodeMemoryRegionPointers()) ||
isIntersectRegions(regionBounds, getDataMemoryRegionPointers()) ||
isIntersectRegions(regionBounds, getObjectMemoryRegionPointers(this)) ||
isIntersectRegions(regionBounds, getArrayMemoryRegionPointers(pointers)) ||
isIntersectRegions(regionBounds, getArrayMemoryRegionPointers(counters)) ||
isIntersectRegions(regionBounds, getArrayMemoryRegionPointers(sizes)) ||
isIntersectRegions(regionBounds, getArrayMemoryRegionPointers(heaps)) ||
isIntersectRegions(regionBounds, getArrayMemoryRegionPointers(catalogues))
) return true;
for(int clength = catalogues.length, int cindex = 0; cindex < clength; cindex++)
{
Heap[] heaps = catalogues[cindex];
if(heaps == null) continue;
if(isIntersectRegions(regionBounds, getCatalogueMemoryRegionPointers(heaps))) return true;
for(int hlength = heaps.length, int hindex = 0; hindex < hlength; hindex++)
{
Heap heap = heaps[hindex];
if(heap == null) continue;
if((hindex & 0x3f) <= 0)
{
final long KB = 1L << 10;
long heapsSize = 64 * KB;
if(cindex > 33) switch(cindex)
{
case 34:
{
heapsSize = 48 * KB;
break;
}
case 35:
{
heapsSize = 32 * KB;
break;
}
case 36:
{
heapsSize = 24 * KB;
break;
}
case 37:
{
heapsSize = 16 * KB;
break;
}
case 38:
{
heapsSize = 12 * KB;
break;
}
case 39:
case 40:
{
heapsSize = 8 * KB;
break;
}
default:
{
heapsSize = 4 * KB;
}
}
long heapsStart = toPointer(heap);
if(isIntersectRegions(regionBounds, new long2 { heapsStart, heapsStart + heapsSize })) return true;
}
if(isIntersectRegions(regionBounds, heap.regionBounds)) return true;
}
}
return false;
}
protected final boolean isMultiThreaded() { return fldMultiThreaded; }
package final void setMultiThreaded() {
if(!fldMultiThreaded)
{
fldMultiThreaded = true;
nowMultiThreaded();
}
}
package final boolean isTerminated() { return fldGCThread.terminated; }
package final Mutex systemOperation { read = fldSystemOperation }
}
class GarbageCollectorThread(Thread)
{
private boolean fldLaunched;
private boolean fldTerminated;
private final Object fldMonitor;
public (Object monitor) { fldMonitor = monitor; }
public void run() {
if(!fldLaunched)
{
fldLaunched = true;
do
{
try
{
Thread.clean();
String.clean();
Runtime.collectGarbage();
pause();
} catch(Exception exception) { }
} while(!fldTerminated);
}
}
public void interruptio() {
throw new SecurityException(package.getResourceString("security.thread.interruptio.gc"));
}
public void terminate() {
synchronized with(fldMonitor)
{
fldTerminated = true;
notify();
}
if(Thread.current() != this) try
{
join();
} catch(Exception exception) { }
}
public boolean terminated { read = fldTerminated }
private void pause() throws InterruptedException {
synchronized with(fldMonitor)
{
wait(6000L);
}
}
}
class Heap(Object)
{
public static final long INSTANCE_SIZE = 0x0400L;
private static final long8 OBJECTS_START = new long8 {
0x0706050403020100L, 0x0f0e0d0c0b0a0908L, 0x1716151413121110L, 0x1f1e1d1c1b1a1918L, 0x2726252423222120L, 0x2f2e2d2c2b2a2928L, 0x3736353433323130L, 0x3f3e3d3c3b3a3938L
};
private static final long8 OBJECTS_STEP = new long8 {
0x4040404040404040L, 0x4040404040404040L, 0x4040404040404040L, 0x4040404040404040L, 0x4040404040404040L, 0x4040404040404040L, 0x4040404040404040L, 0x4040404040404040L
};
private static native void initObjectsPointers(byte[] objPtrs);
private int fldCatalogueIndex;
private int fldHeapIndex;
private int fldObjectsAllocated;
private int fldObjectsLength;
private int fldGCVisited;
private int fldGCAttained;
private int fldGCLength;
private int fldLock;
private long fldObjectSize;
private long fldRegionPointer;
private long2 fldRegionBounds;
private byte[] fldObjectsPointers;
private byte[] fldGCPointers;
private byte[] fldGCAttainability;
public () { }
public void initForGC() {
clearAttainability();
enterLock();
try
{
copyPointers();
fldGCVisited = 0;
fldGCAttained = 0;
fldGCLength = fldObjectsAllocated;
} finally
{
leaveLock();
}
}
public void finForGC() {
fldGCVisited = 0;
fldGCAttained = 0;
fldGCLength = 0;
}
public void makeAttainedInstancePointer(long instancePtr) {
int length = fldGCLength;
if(length <= 0) return;
int comp = (int) ((instancePtr - fldRegionPointer) / fldObjectSize);
if(getAttainability(comp)) return;
byte[] pointers = fldGCPointers;
int attained = fldGCAttained;
label0: if((pointers[attained] & 0xffi) != comp)
{
for(int bidx = attained + 1, int eidx = length - 1; bidx <= eidx; )
{
int midx = bidx + eidx >>> 1;
int curr = pointers[midx] & 0xffi;
if(comp == curr)
{
Array.copy(pointers, attained, pointers, attained + 1, midx - attained);
pointers[attained] = (byte) comp;
break label0;
}
if(comp < curr)
{
eidx = midx - 1;
continue;
}
bidx = midx + 1;
}
return;
}
setAttainability(comp);
fldGCAttained = attained + 1;
}
public void releaseInstancePointer(long instancePtr) {
byte[] pointers = fldObjectsPointers;
int allocated = fldObjectsAllocated - 1;
int comp = (int) ((instancePtr - fldRegionPointer) / fldObjectSize);
if((pointers[allocated] & 0xffi) != comp)
{
for(int bidx = 0, int eidx = allocated - 1; bidx <= eidx; )
{
int midx = bidx + eidx >>> 1;
int curr = pointers[midx] & 0xffi;
if(comp == curr)
{
Array.copy(pointers, midx + 1, pointers, midx, allocated - midx);
break;
}
if(comp < curr)
{
eidx = midx - 1;
continue;
}
bidx = midx + 1;
}
pointers[allocated] = (byte) comp;
}
fldObjectsAllocated = allocated;
}
public void captureInstancePointer() {
byte[] pointers = fldObjectsPointers;
int allocated = fldObjectsAllocated;
int comp = pointers[allocated] & 0xffi;
int eidx = allocated - 1;
boolean lock = false;
try
{
if(eidx >= 0 && comp < (pointers[eidx] & 0xffi))
{
int bidx = 0;
do
{
int midx = bidx + eidx >>> 1;
if(comp >= (pointers[midx] & 0xffi))
{
bidx = midx + 1;
continue;
}
int pidx = midx - 1;
if(pidx < 0 || comp > (pointers[pidx] & 0xffi))
{
lock = true;
enterLock();
Array.copy(pointers, midx, pointers, midx + 1, allocated - midx);
pointers[midx] = (byte) comp;
break;
}
eidx = pidx;
} while(bidx <= eidx);
}
fldObjectsAllocated = allocated + 1;
} finally
{
if(lock) leaveLock();
}
}
public boolean isFull() { return fldObjectsAllocated >= fldObjectsLength; }
public boolean isOwnInstancePointer(long instancePtr) { return (instancePtr -= fldRegionPointer) >= 0 && instancePtr < fldObjectSize * fldObjectsLength; }
public long getNextInstancePointer() { return fldRegionPointer + fldObjectSize * (fldObjectsPointers[fldObjectsAllocated] & 0xffL); }
public int length { read = fldGCLength }
public int attained { read = fldGCAttained }
public int visited { read = fldGCVisited, write = fldGCVisited }
public int catalogueIndex { read = fldCatalogueIndex }
public int heapIndex { read = fldHeapIndex }
public long objectSize { read = fldObjectSize }
public long regionPointer { read = fldRegionPointer }
public long2 regionBounds { read = fldRegionBounds }
public long operator [](int index) { return fldRegionPointer + fldObjectSize * (fldGCPointers[index] & 0xffL); }
void init(int catalogueIndex, int heapIndex, long regionPtr, long objectSize, int objectsLength) {
long thisPtr = Runtime.toPointer(this);
byte[] objPtrs = (byte[]) Runtime.initArray(thisPtr + 0x0140L, byte[].class, Runtime.ARRAY_HEADER_SIZE, objectsLength, thisPtr + 0x0200L, null);
byte[] gcPtrs = (byte[]) Runtime.initArray(thisPtr + 0x0180L, byte[].class, Runtime.ARRAY_HEADER_SIZE, objectsLength, thisPtr + 0x0300L, null);
byte[] gcAtt = (byte[]) Runtime.initArray(thisPtr + 0x01c0L, byte[].class, Runtime.ARRAY_HEADER_SIZE, 32, thisPtr + 0x0120L, null);
initObjectsPointers(objPtrs);
fldCatalogueIndex = catalogueIndex;
fldHeapIndex = heapIndex;
fldObjectsLength = objectsLength;
fldObjectSize = objectSize;
fldRegionPointer = regionPtr;
fldRegionBounds = new long2 { regionPtr, regionPtr + objectSize * objectsLength };
fldObjectsPointers = objPtrs;
fldGCPointers = gcPtrs;
fldGCAttainability = gcAtt;
}
private native void enterLock();
private void leaveLock() { fldLock = 0; }
private native void copyPointers();
private native void clearAttainability();
private native void setAttainability(int compressedPtr);
private native boolean getAttainability(int compressedPtr);
}