/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package java.lang;
public final class Memory extends Object
{
private static final int OFFSET_MONITOR = -0x04;
private static final int OFFSET_OBJCLASS = +0x04;
private static final int OFFSET_LENGTH = +0x08;
private static final int OFFSET_DISPLACEMENT = +0x0c;
private static final int OFFSET_CONTENT = +0x10;
private static final int REF_TO_BLOCK = -0x04;
private static final int BLOCK_TO_REF = -REF_TO_BLOCK;
private static final int SIZE_HEAD_OBJECT = 0x0c;
private static final int SIZE_HEAD_ARRAY = SIZE_HEAD_OBJECT + 0x08;
private static boolean MULTI_THREADED;
private static boolean RESERVE_ACTIVE;
private static int STRING_POOL_OFFSET; /* СИСТЕМНОЕ ПОЛЕ */
private static int DESCRIPTORS_SIZE; /* СИСТЕМНОЕ ПОЛЕ */
private static int HEAP_LIMIT; /* СИСТЕМНОЕ ПОЛЕ */
private static int HEAP_BEGIN;
private static int HEAP_RESERVE;
private static int DESCRIPTORS_COUNT;
private static int DESCRIPTORS_RESERVE;
private static long COLLECTED_BYTES;
private static int[] FINALIZING_REF_STACK;
private static long[] DESCRIPTORS;
private static OutOfMemoryError LACK_MEMORY_ERROR;
private static NoClassDefFoundError NOT_DEFINED_CLASS_ERROR;
static {
int len;
int ref;
int block = (len = STRING_POOL_OFFSET) + 0x04;
for(int splen = MalikSystem.getIntAt(len), i = 0; i < splen; i++) block += needMemory(MalikSystem.getIntAt(block + (BLOCK_TO_REF + OFFSET_LENGTH)));
ref = (block += -block & 0x0f) + BLOCK_TO_REF;
MalikSystem.setIntAt(ref, 0);
MalikSystem.setIntAt(ref + OFFSET_MONITOR, 0);
MalikSystem.setIntAt(ref + OFFSET_OBJCLASS, 0);
MalikSystem.setObjectAt(ref + OFFSET_OBJCLASS, MalikSystem.getClassInstance("[J"));
MalikSystem.setIntAt(ref + OFFSET_LENGTH, len = (DESCRIPTORS_SIZE - SIZE_HEAD_ARRAY) >> 3);
MalikSystem.setIntAt(ref + OFFSET_DISPLACEMENT, 0);
block += (len << 3) + SIZE_HEAD_ARRAY;
MULTI_THREADED = false;
RESERVE_ACTIVE = false;
HEAP_BEGIN = (block += (-block & 0x0f));
HEAP_RESERVE = (HEAP_LIMIT - HEAP_BEGIN) / 20;
DESCRIPTORS_COUNT = 0;
DESCRIPTORS_RESERVE = len - len / 20;
COLLECTED_BYTES = 0L;
DESCRIPTORS = (long[]) MalikSystem.convertToObject(ref);
}
public static int getFree() {
boolean thread;
boolean status;
int result;
status = (thread = MULTI_THREADED) && MalikSystem.enterMonopolyAccess();
try
{
result = free();
}
finally
{
if(thread) MalikSystem.leaveMonopolyAccess(status);
}
return result;
}
public static int getTotal() {
return HEAP_LIMIT - HEAP_BEGIN;
}
public static long getCollected() {
return COLLECTED_BYTES;
}
public static Object[] getAllObjects() {
boolean thread;
boolean status;
Object[] result;
status = (thread = MULTI_THREADED) && MalikSystem.enterMonopolyAccess();
try
{
int rlen;
result = new Object[rlen = DESCRIPTORS_COUNT - MalikSystem.arrayfindf_int(FINALIZING_REF_STACK, 0, 0)];
for(int slen = FINALIZING_REF_STACK.length, dlen = DESCRIPTORS_COUNT, i, j = i = 0; i < rlen && j < dlen; j++)
{
int ref = (int) DESCRIPTORS[j] + BLOCK_TO_REF;
Object reference;
if(MalikSystem.arrayfindf_int(FINALIZING_REF_STACK, 0, ref) >= slen && (reference = MalikSystem.convertToObject(ref)) != result) result[i++] = reference;
}
}
finally
{
if(thread) MalikSystem.leaveMonopolyAccess(status);
}
return result;
}
static void completeInit() {
FINALIZING_REF_STACK = new int[0x20];
LACK_MEMORY_ERROR = new OutOfMemoryError("Невозможно создать новый объект: динамическая память заполнена.");
NOT_DEFINED_CLASS_ERROR = new NoClassDefFoundError("Невозможно создать новый объект: класс создаваемого объекта не указан.");
}
static void setMultiThreaded() {
MULTI_THREADED = true;
}
static void checkSize(long refSize) throws OutOfMemoryError {
if(refSize > 0x000000007fffffecL)
{
throw LACK_MEMORY_ERROR;
}
}
static boolean isHeapAddress(int beginAddress, int endAddress) {
return (beginAddress > STRING_POOL_OFFSET || endAddress > STRING_POOL_OFFSET) && (beginAddress < HEAP_LIMIT || endAddress < HEAP_LIMIT);
}
static int getStringPoolOffset() {
return STRING_POOL_OFFSET;
}
static long collectGarbage() {
long result = 0L;
long lastRunTime = System.currentTimeMillis() - 1000L;
label0: for(int i = 0; i < DESCRIPTORS_COUNT; i++)
{
boolean found;
boolean status;
int esp;
int ebp;
int ref;
int block;
long deallocated;
long elapsedTime;
long currentTime;
/* Примерно каждую секунду удаляем все объекты с нулевым количеством ссылок на них */
if((elapsedTime = (currentTime = System.currentTimeMillis()) - lastRunTime) >= 1000L || elapsedTime < 0L) for(lastRunTime = currentTime, block = ref = 0; ; )
{
status = MalikSystem.enterMonopolyAccess();
try
{
int index;
if(found = (index = DESCRIPTORS_COUNT - 1) >= 0 && (index = MalikSystem.findzerob(DESCRIPTORS, index, BLOCK_TO_REF)) >= 0)
{
FINALIZING_REF_STACK[0] = ref = (block = (int) DESCRIPTORS[index]) + BLOCK_TO_REF;
}
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
if(!found) break;
try
{
MalikSystem.convertToObject(ref).$finalize$();
}
catch(Throwable e)
{
}
status = MalikSystem.enterMonopolyAccess();
try
{
deallocated = (long) deallocate(MalikSystem.blockfindb(DESCRIPTORS, DESCRIPTORS_COUNT - 1, block));
FINALIZING_REF_STACK[0] = 0;
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
result += deallocated;
COLLECTED_BYTES += deallocated;
}
/* В остальное время: */
/* 1. Удаляем объект, все ссылки на который ведут только из него самого */
for(; ; )
{
if((ref = (block = (int) DESCRIPTORS[i]) + BLOCK_TO_REF) == BLOCK_TO_REF) break label0;
if(StringPool.isMyOwnedObject(MalikSystem.convertToObject(ref))) continue label0;
status = MalikSystem.enterMonopolyAccess();
try
{
if(found = MalikSystem.getIntAt(ref) == MalikSystem.convertToObject(ref).getQuantityOfReferencesTo(ref)) FINALIZING_REF_STACK[0] = ref;
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
if(!found) break;
try
{
MalikSystem.convertToObject(ref).$finalize$();
}
catch(Throwable e)
{
}
status = MalikSystem.enterMonopolyAccess();
try
{
deallocated = (long) deallocate(MalikSystem.blockfindb(DESCRIPTORS, DESCRIPTORS_COUNT - 1, block));
FINALIZING_REF_STACK[0] = 0;
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
result += deallocated;
COLLECTED_BYTES += deallocated;
}
/* 2. Удаляем «острова изоляции» (группа объектов, которые ссылаются друг на друга и не имеют других ссылок на себя) */
if((ref = (int) DESCRIPTORS[i] + BLOCK_TO_REF) == BLOCK_TO_REF) break label0;
if(StringPool.isMyOwnedObject(MalikSystem.convertToObject(ref))) continue label0;
for(esp = 1, FINALIZING_REF_STACK[ebp = 0] = ref; ebp < esp; ebp++)
{
int refCount = 0;
ref = FINALIZING_REF_STACK[ebp];
for(int j = 0; j < DESCRIPTORS_COUNT; j++)
{
int count;
int refAnot;
if((j & 0x03ff) == 0x03ff && ((elapsedTime = (currentTime = System.currentTimeMillis()) - lastRunTime) >= 1000L || elapsedTime < 0L))
{
for(lastRunTime = currentTime, block = refAnot = 0; ; )
{
status = MalikSystem.enterMonopolyAccess();
try
{
int index;
found =
(index = DESCRIPTORS_COUNT - 1) >= 0 &&
(index = MalikSystem.findzerob(DESCRIPTORS, index, BLOCK_TO_REF)) >= 0 &&
push(refAnot = (block = (int) DESCRIPTORS[index]) + BLOCK_TO_REF, esp)
;
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
if(!found) break;
try
{
MalikSystem.convertToObject(refAnot).$finalize$();
}
catch(Throwable e)
{
}
status = MalikSystem.enterMonopolyAccess();
try
{
deallocated = (long) deallocate(MalikSystem.blockfindb(DESCRIPTORS, DESCRIPTORS_COUNT - 1, block));
FINALIZING_REF_STACK[esp] = 0;
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
result += deallocated;
COLLECTED_BYTES += deallocated;
}
}
if((refAnot = (int) DESCRIPTORS[j] + BLOCK_TO_REF) == BLOCK_TO_REF) break;
status = MalikSystem.enterMonopolyAccess();
try
{
if(found = (count = MalikSystem.convertToObject(refAnot).getQuantityOfReferencesTo(ref)) > 0 && push(refAnot, esp)) esp++;
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
if(found) refCount += count;
}
if(refCount < MalikSystem.getIntAt(ref))
{
MalikSystem.arrayfill_int(FINALIZING_REF_STACK, 0, esp, 0);
continue label0;
}
}
for(int j = esp; j-- > 0; )
{
try
{
MalikSystem.convertToObject(FINALIZING_REF_STACK[j]).$finalize$();
}
catch(Throwable e)
{
}
}
for(int j = esp; j-- > 0; )
{
status = MalikSystem.enterMonopolyAccess();
try
{
deallocated = (long) deallocate(MalikSystem.blockfindb(DESCRIPTORS, DESCRIPTORS_COUNT - 1, FINALIZING_REF_STACK[j] + REF_TO_BLOCK));
if(j == 0) MalikSystem.arrayfill_int(FINALIZING_REF_STACK, 0, esp, 0);
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
result += deallocated;
COLLECTED_BYTES += deallocated;
}
}
return result;
}
static Object intern(Object instance) {
boolean thread;
boolean status;
Object result;
Class instanceClass;
if((result = instance) == null) return null;
instanceClass = instance.getClass();
status = (thread = MULTI_THREADED) && MalikSystem.enterMonopolyAccess();
try
{
for(int slen = FINALIZING_REF_STACK.length, i = 0; i < DESCRIPTORS_COUNT; i++)
{
int ref = (int) DESCRIPTORS[i] + BLOCK_TO_REF;
if(
MalikSystem.arrayfindf_int(FINALIZING_REF_STACK, 0, ref) >= slen &&
MalikSystem.getObjectAt(ref + OFFSET_OBJCLASS) == instanceClass &&
MalikSystem.convertToObject(ref).equals(instance)
)
{
result = MalikSystem.convertToObject(ref);
break;
}
}
}
finally
{
if(thread) MalikSystem.leaveMonopolyAccess(status);
}
return result;
}
static Object internIgnore(Object instance) {
boolean thread;
boolean status;
Object result;
Class instanceClass;
if((result = instance) == null) return null;
instanceClass = instance.getClass();
status = (thread = MULTI_THREADED) && MalikSystem.enterMonopolyAccess();
try
{
for(int slen = FINALIZING_REF_STACK.length, i = 0; i < DESCRIPTORS_COUNT; i++)
{
int ref = (int) DESCRIPTORS[i] + BLOCK_TO_REF;
if(
MalikSystem.arrayfindf_int(FINALIZING_REF_STACK, 0, ref) >= slen && ref != MalikSystem.convertToReference(instance) &&
MalikSystem.getObjectAt(ref + OFFSET_OBJCLASS) == instanceClass && MalikSystem.convertToObject(ref).equals(instance)
)
{
result = MalikSystem.convertToObject(ref);
break;
}
}
}
finally
{
if(thread) MalikSystem.leaveMonopolyAccess(status);
}
return result;
}
static Object allocateInstanceOf(Class instanceClass, int refSize, int arrayLength) throws OutOfMemoryError, NoClassDefFoundError {
boolean thread;
boolean status;
int blockSize;
Object result;
if(instanceClass == null)
{
throw NOT_DEFINED_CLASS_ERROR;
}
if(refSize <= 0) return null;
blockSize = refSize - REF_TO_BLOCK;
refSize = (blockSize += -blockSize & 0x0f) - BLOCK_TO_REF;
status = (thread = MULTI_THREADED) && MalikSystem.enterMonopolyAccess();
try
{
result = makeObject(instanceClass, allocate(blockSize) + BLOCK_TO_REF, refSize, arrayLength);
}
finally
{
if(thread) MalikSystem.leaveMonopolyAccess(status);
}
return result;
}
private static void outOfMemory() throws OutOfMemoryError {
if(RESERVE_ACTIVE)
{
/* Выходим из программы, если резерв памяти был исчерпан */
MalikSystem.syscall((long) Thread.MAIN_THREAD_ID, 0x0001);
}
RESERVE_ACTIVE = true;
throw LACK_MEMORY_ERROR;
}
private static boolean push(int ref, int top) {
if(MalikSystem.arrayfindf_int(FINALIZING_REF_STACK, 0, ref) < top) return false;
if(top == FINALIZING_REF_STACK.length) MalikSystem.arraycopyf_int(FINALIZING_REF_STACK, 0, FINALIZING_REF_STACK = new int[top << 1], 0, top);
FINALIZING_REF_STACK[top] = ref;
return true;
}
private static int free() {
int i;
long descriptor;
return HEAP_LIMIT - ((i = DESCRIPTORS_COUNT - 1) >= 0 ? (int) (descriptor = DESCRIPTORS[i]) + (int) (descriptor >> 32) : HEAP_BEGIN);
}
private static int allocate(int blockSize) throws OutOfMemoryError {
int i;
int result;
long descriptor;
if(RESERVE_ACTIVE && (DESCRIPTORS_COUNT < DESCRIPTORS_RESERVE || free() > HEAP_RESERVE)) RESERVE_ACTIVE = false;
if(DESCRIPTORS_COUNT >= (RESERVE_ACTIVE ? DESCRIPTORS.length : DESCRIPTORS_RESERVE)) outOfMemory();
if(DESCRIPTORS_COUNT == 0)
{
if(blockSize > HEAP_LIMIT - HEAP_BEGIN) outOfMemory();
DESCRIPTORS[DESCRIPTORS_COUNT++] = makeDescriptor(HEAP_BEGIN, blockSize);
return HEAP_BEGIN;
}
if((i = MalikSystem.findfreef(DESCRIPTORS, 0, blockSize)) > 0 && i < DESCRIPTORS_COUNT)
{
MalikSystem.arraycopyb_long(DESCRIPTORS, DESCRIPTORS_COUNT, DESCRIPTORS, DESCRIPTORS_COUNT + 1, DESCRIPTORS_COUNT++ - i);
DESCRIPTORS[i] = makeDescriptor(result = (int) DESCRIPTORS[i] - blockSize, blockSize);
return result;
}
i = DESCRIPTORS_COUNT - 1;
if(blockSize > HEAP_LIMIT - (result = (int) (descriptor = DESCRIPTORS[i]) + (int) (descriptor >> 32))) outOfMemory();
DESCRIPTORS[DESCRIPTORS_COUNT++] = makeDescriptor(result, blockSize);
return result;
}
private static int deallocate(int blockIndex) {
if(blockIndex >= 0)
{
int result = (int) (DESCRIPTORS[blockIndex] >> 32);
MalikSystem.arraycopyf_long(DESCRIPTORS, blockIndex + 1, DESCRIPTORS, blockIndex, --DESCRIPTORS_COUNT - blockIndex);
DESCRIPTORS[DESCRIPTORS_COUNT] = 0L;
return result;
}
return 0;
}
private static int needMemory(int length) {
return length + (-length & 3) + SIZE_HEAD_ARRAY;
}
private static long makeDescriptor(int block, int blockSize) {
return (long) blockSize << 32 | (long) block & 0x00000000ffffffffL;
}
private static Object makeObject(Class instanceClass, int ref, int refSize, int arrayLength) {
Object result;
MalikSystem.setIntAt(ref, 0);
MalikSystem.setIntAt(ref + OFFSET_MONITOR, 0);
MalikSystem.setIntAt(ref + OFFSET_OBJCLASS, 0);
MalikSystem.setObjectAt(ref + OFFSET_OBJCLASS, instanceClass);
result = MalikSystem.convertToObject(ref);
if(refSize > OFFSET_CONTENT)
{
int len;
MalikSystem.setIntAt(ref + OFFSET_LENGTH, len = (refSize - 0x10) >> 2);
MalikSystem.setIntAt(ref + OFFSET_DISPLACEMENT, 0);
MalikSystem.arrayfill_int(result, 0, len, 0);
}
MalikSystem.setIntAt(ref + OFFSET_LENGTH, arrayLength >= 0 ? arrayLength : 0);
return result;
}
private Memory() {
}
}
final class StringPool extends Object
{
private static final int LENGTH;
private static final byte[][] CODES;
private static final String[] STRINGS;
static {
int address;
int length = MalikSystem.getIntAt(address = Memory.getStringPoolOffset());
byte[][] codes;
address += 0x04;
LENGTH = length;
CODES = codes = new byte[length][];
STRINGS = new String[length];
for(int i = 0; i < length; i++)
{
int size = (codes[i] = readArray(address)).length;
address += size + (-size & 0x03) + 0x14;
}
Memory.completeInit();
Thread.completeInit();
}
public static int getLength() {
return LENGTH;
}
public static String getString(int index) {
boolean flag;
String[] strings;
String result;
if(index >= LENGTH || index < 0) return null;
if((result = (strings = STRINGS)[index]) != null) return result;
flag = MalikSystem.enterMonopolyAccess();
try
{
if(strings[index] == null) strings[index] = result = (String) Memory.internIgnore(new String(CODES[index]));
}
finally
{
MalikSystem.leaveMonopolyAccess(flag);
}
return result;
}
static boolean isMyOwnedObject(Object obj) {
return obj == CODES || obj == STRINGS || Array.findf(STRINGS, 0, obj) < LENGTH;
}
static String intern(String string) {
String[] strings = STRINGS;
String result = string;
for(int index = LENGTH; index-- > 0; )
{
String current;
if((current = strings[index]) != null && current.equals(string))
{
result = current;
break;
}
}
return result;
}
private static byte[] readArray(int address) {
return (byte[]) MalikSystem.convertToObject(address + 0x04);
}
private StringPool() {
}
}