mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
work on LaxMalloc
This commit is contained in:
parent
2cd9e7f3df
commit
2b73f658d0
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.runtime;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
/**
|
||||
|
@ -30,6 +31,7 @@ import org.teavm.interop.Unmanaged;
|
|||
* @author lax1dude
|
||||
*/
|
||||
@Unmanaged
|
||||
@StaticInit
|
||||
public final class LaxMalloc {
|
||||
|
||||
private LaxMalloc() {
|
||||
|
@ -45,6 +47,13 @@ public final class LaxMalloc {
|
|||
private static final int ADDR_HEAP_BUCKETS_START = 16; // Address to the list of 64 pointers to the beginnings of the 64 buckets
|
||||
private static final int ADDR_HEAP_DATA_START = 272; // Beginning of the first chunk of the heap
|
||||
|
||||
static {
|
||||
// zero out the control region
|
||||
Allocator.fillZero(Address.fromInt(0), ADDR_HEAP_DATA_START);
|
||||
// initialize heap limit
|
||||
Address.fromInt(ADDR_HEAP_LIMIT).putInt(ADDR_HEAP_DATA_START);
|
||||
}
|
||||
|
||||
/**
|
||||
* malloc implementation
|
||||
*/
|
||||
|
@ -60,8 +69,8 @@ public final class LaxMalloc {
|
|||
}
|
||||
|
||||
private static Address laxAlloc(int sizeBytes, boolean cleared) {
|
||||
if(sizeBytes == 0) {
|
||||
// Produce a null pointer if 0 size if requested
|
||||
if(sizeBytes <= 0) {
|
||||
// Produce a null pointer if 0 or invalid size is requested
|
||||
return Address.fromInt(0);
|
||||
}
|
||||
|
||||
|
@ -73,26 +82,61 @@ public final class LaxMalloc {
|
|||
// always between 0-63
|
||||
int bucket = getListBucket(sizeBytes);
|
||||
|
||||
if(bucket == 63) {
|
||||
// special bucket for the huge allocations
|
||||
// uses a different function
|
||||
return laxHugeAlloc(sizeBytes, cleared);
|
||||
}
|
||||
|
||||
long bucketMask = Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
||||
|
||||
// test the bucket mask if the bucket has any free chunks
|
||||
if((bucketMask & (1L << bucket)) == 0l) {
|
||||
// no more free chunks, let us first check if there is are any
|
||||
// no more free chunks, let us first check if there are any
|
||||
// chunks in the larger buckets we can split
|
||||
long largerBucketsMask = (bucketMask & (0xFFFFFFFFFFFFFFFFL << (bucket + 1)));
|
||||
if(largerBucketsMask != 0l) {
|
||||
// at least one larger chunk exists
|
||||
int largerBucket = Long.numberOfTrailingZeros(largerBucketsMask);
|
||||
// we can quickly find it using the bitmask
|
||||
int largerBucket = numberOfTrailingZerosL(largerBucketsMask);
|
||||
|
||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(largerBucket << SIZEOF_PTR_SH);
|
||||
Address chunkPtr = bucketStartAddr.getAddress();
|
||||
//TODO: remove chunk from old bucket
|
||||
int chunkSize = readChunkSize(chunkPtr);
|
||||
int chunkOtherHalfNewSize = chunkSize - sizeBytes;
|
||||
//TODO
|
||||
//TODO
|
||||
//TODO
|
||||
|
||||
return null; //TODO
|
||||
int chunkNewSize = chunkSize - sizeBytes - 8; // -size - 2 ints - 2 more ints
|
||||
|
||||
// if the other half of the new chunk is too small, check an even larger bucket
|
||||
// we should only need to look at an even larger bucket one more time before giving up
|
||||
if(chunkNewSize - 8 < MIN_ALLOC_SIZE) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
// remove the large chunk from its bucket
|
||||
unlinkChunkFromFreeList(chunkPtr, chunkSize);
|
||||
|
||||
// provision the part of the large chunk we want
|
||||
int sizePlusInts = sizeBytes + 8; // size + 2 ints
|
||||
chunkPtr.putInt(sizePlusInts | 0x80000000); // size + in use flag
|
||||
chunkPtr.add(sizeBytes + 4).putInt(sizePlusInts); // size integer at the end
|
||||
|
||||
// provision the other part of the chunk that we want to return to the free list
|
||||
Address otherChunkPtr = chunkPtr.add(sizePlusInts);
|
||||
otherChunkPtr.putInt(chunkNewSize); // size
|
||||
otherChunkPtr.add(chunkNewSize - 4).putInt(chunkNewSize); // size (end)
|
||||
|
||||
// return the other part of the chunk to the free chunks list
|
||||
linkChunkInFreeList(otherChunkPtr, chunkNewSize);
|
||||
|
||||
// +4 bytes to skip size
|
||||
Address ret = chunkPtr.add(4);
|
||||
|
||||
// clear if requested
|
||||
if(cleared) {
|
||||
Allocator.fillZero(ret, sizeBytes);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}else {
|
||||
// No larger chunks already exist that we can split,
|
||||
// time to sbrk
|
||||
|
@ -109,7 +153,7 @@ public final class LaxMalloc {
|
|||
newChunk.add(sizeBytes + 4).putInt(sizePlusInts); // size integer at the end
|
||||
|
||||
// return the chunk, +4 bytes to skip size int
|
||||
// we don't need to clear it because its new
|
||||
// we don't need to clear it because its new memory
|
||||
return newChunk.add(4);
|
||||
}
|
||||
}else {
|
||||
|
@ -148,6 +192,10 @@ public final class LaxMalloc {
|
|||
}
|
||||
}
|
||||
|
||||
private static Address laxHugeAlloc(int sizeBytes, boolean cleared) {
|
||||
return null; //TODO: bucket number 63
|
||||
}
|
||||
|
||||
/**
|
||||
* free implementation<br><br>
|
||||
*
|
||||
|
@ -174,7 +222,14 @@ public final class LaxMalloc {
|
|||
if((prevChunkSize & 0x80000000) == 0) {
|
||||
// previous chunk is not in use, merge!
|
||||
|
||||
//TODO
|
||||
// remove the previous chunk from its list
|
||||
unlinkChunkFromFreeList(prevChunkPtr, prevChunkSize);
|
||||
|
||||
// resize the current chunk to also contain the previous chunk
|
||||
chunkPtr = prevChunkPtr;
|
||||
chunkSize += prevChunkSize;
|
||||
chunkPtr.putInt(chunkSize);
|
||||
chunkPtr.add(chunkSize).putInt(chunkSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,11 +239,22 @@ public final class LaxMalloc {
|
|||
int nextChunkSize = readChunkSizeStatus(nextChunkPtr);
|
||||
if((nextChunkSize & 0x80000000) == 0) {
|
||||
// next chunk is not in use, merge!
|
||||
|
||||
// remove the next chunk from its list
|
||||
unlinkChunkFromFreeList(nextChunkPtr, nextChunkSize);
|
||||
|
||||
//TODO
|
||||
// resize the current chunk to also contain the next chunk
|
||||
chunkSize += nextChunkSize;
|
||||
chunkPtr.putInt(chunkSize);
|
||||
chunkPtr.add(chunkSize).putInt(chunkSize);
|
||||
}
|
||||
}
|
||||
|
||||
// add the final chunk to the free chunks list
|
||||
linkChunkInFreeList(chunkPtr, chunkSize);
|
||||
}
|
||||
|
||||
private static void linkChunkInFreeList(Address chunkPtr, int chunkSize) {
|
||||
int bucket = getListBucket(chunkSize - 8); // size - 2 ints
|
||||
|
||||
long bucketMask = Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
||||
|
@ -211,7 +277,53 @@ public final class LaxMalloc {
|
|||
writeChunkPrevFreeAddr(chunkPtr, Address.fromInt(0));
|
||||
bucketStartAddr.putAddress(chunkPtr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void unlinkChunkFromFreeList(Address chunkPtr, int chunkSize) {
|
||||
Address prevChunkPtr = readChunkPrevFreeAddr(chunkPtr);
|
||||
Address nextChunkPtr = readChunkNextFreeAddr(chunkPtr);
|
||||
if((prevChunkPtr.toInt() | nextChunkPtr.toInt()) == 0) {
|
||||
// chunk is the only one currently in its bucket
|
||||
|
||||
int chunkBucket = getListBucket(chunkSize - 8); // size - 2 ints
|
||||
|
||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(chunkBucket << SIZEOF_PTR_SH);
|
||||
bucketStartAddr.putAddress(Address.fromInt(0)); // remove chunk from the bucket
|
||||
|
||||
// clear the bit in the free buckets bitmask
|
||||
long bucketsFreeMask = Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
||||
bucketsFreeMask &= ~(1L << chunkBucket);
|
||||
Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).putLong(bucketsFreeMask);
|
||||
|
||||
}else {
|
||||
// there are other chunks in this bucket
|
||||
|
||||
if(prevChunkPtr.toInt() != 0) {
|
||||
// previous chunk exists
|
||||
|
||||
if(nextChunkPtr.toInt() != 0) {
|
||||
// next chunk exits, link it to the previous chunk
|
||||
writeChunkNextFreeAddr(prevChunkPtr, nextChunkPtr);
|
||||
writeChunkPrevFreeAddr(nextChunkPtr, prevChunkPtr);
|
||||
}else {
|
||||
// there is no next chunk
|
||||
writeChunkNextFreeAddr(prevChunkPtr, Address.fromInt(0));
|
||||
}
|
||||
|
||||
}else {
|
||||
// no previous chunk, this must be the first chunk in the bucket
|
||||
|
||||
int chunkBucket = getListBucket(chunkSize - 8); // size - 2 ints
|
||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(chunkBucket << SIZEOF_PTR_SH);
|
||||
|
||||
// we already know the next chunk exists
|
||||
// make the next chunk the first chunk in the bucket
|
||||
bucketStartAddr.putAddress(nextChunkPtr);
|
||||
|
||||
// unlink the next chunk from the current chunk
|
||||
writeChunkPrevFreeAddr(nextChunkPtr, Address.fromInt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int NUM_FREE_BUCKETS = 64;
|
||||
|
@ -224,7 +336,7 @@ public final class LaxMalloc {
|
|||
if (allocSize < 128)
|
||||
return (allocSize >> 3) - 1;
|
||||
|
||||
int clz = Integer.numberOfLeadingZeros(allocSize);
|
||||
int clz = numberOfLeadingZerosI(allocSize);
|
||||
int bucketIndex = (clz > 19) ? 110 - (clz << 2) + ((allocSize >> (29 - clz)) ^ 4)
|
||||
: min(71 - (clz << 1) + ((allocSize >> (30 - clz)) ^ 2), NUM_FREE_BUCKETS - 1);
|
||||
|
||||
|
@ -282,4 +394,14 @@ public final class LaxMalloc {
|
|||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
private static int numberOfTrailingZerosL(long i) {
|
||||
//TODO: Intrinsify this, WASM has dedicated instructions for this operation!!!
|
||||
return Long.numberOfTrailingZeros(i);
|
||||
}
|
||||
|
||||
private static int numberOfLeadingZerosI(int i) {
|
||||
//TODO: Intrinsify this, WASM has dedicated instructions for this operation!!!
|
||||
return Integer.numberOfLeadingZeros(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user