mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
work on LaxMalloc
This commit is contained in:
parent
2cd9e7f3df
commit
2b73f658d0
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.runtime;
|
package org.teavm.runtime;
|
||||||
|
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.interop.StaticInit;
|
||||||
import org.teavm.interop.Unmanaged;
|
import org.teavm.interop.Unmanaged;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +31,7 @@ import org.teavm.interop.Unmanaged;
|
||||||
* @author lax1dude
|
* @author lax1dude
|
||||||
*/
|
*/
|
||||||
@Unmanaged
|
@Unmanaged
|
||||||
|
@StaticInit
|
||||||
public final class LaxMalloc {
|
public final class LaxMalloc {
|
||||||
|
|
||||||
private 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_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
|
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
|
* malloc implementation
|
||||||
*/
|
*/
|
||||||
|
@ -60,8 +69,8 @@ public final class LaxMalloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Address laxAlloc(int sizeBytes, boolean cleared) {
|
private static Address laxAlloc(int sizeBytes, boolean cleared) {
|
||||||
if(sizeBytes == 0) {
|
if(sizeBytes <= 0) {
|
||||||
// Produce a null pointer if 0 size if requested
|
// Produce a null pointer if 0 or invalid size is requested
|
||||||
return Address.fromInt(0);
|
return Address.fromInt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,26 +82,61 @@ public final class LaxMalloc {
|
||||||
// always between 0-63
|
// always between 0-63
|
||||||
int bucket = getListBucket(sizeBytes);
|
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();
|
long bucketMask = Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
||||||
|
|
||||||
// test the bucket mask if the bucket has any free chunks
|
// test the bucket mask if the bucket has any free chunks
|
||||||
if((bucketMask & (1L << bucket)) == 0l) {
|
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
|
// chunks in the larger buckets we can split
|
||||||
long largerBucketsMask = (bucketMask & (0xFFFFFFFFFFFFFFFFL << (bucket + 1)));
|
long largerBucketsMask = (bucketMask & (0xFFFFFFFFFFFFFFFFL << (bucket + 1)));
|
||||||
if(largerBucketsMask != 0l) {
|
if(largerBucketsMask != 0l) {
|
||||||
// at least one larger chunk exists
|
// 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 bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(largerBucket << SIZEOF_PTR_SH);
|
||||||
Address chunkPtr = bucketStartAddr.getAddress();
|
Address chunkPtr = bucketStartAddr.getAddress();
|
||||||
//TODO: remove chunk from old bucket
|
|
||||||
int chunkSize = readChunkSize(chunkPtr);
|
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 {
|
}else {
|
||||||
// No larger chunks already exist that we can split,
|
// No larger chunks already exist that we can split,
|
||||||
// time to sbrk
|
// time to sbrk
|
||||||
|
@ -109,7 +153,7 @@ public final class LaxMalloc {
|
||||||
newChunk.add(sizeBytes + 4).putInt(sizePlusInts); // size integer at the end
|
newChunk.add(sizeBytes + 4).putInt(sizePlusInts); // size integer at the end
|
||||||
|
|
||||||
// return the chunk, +4 bytes to skip size int
|
// 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);
|
return newChunk.add(4);
|
||||||
}
|
}
|
||||||
}else {
|
}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>
|
* free implementation<br><br>
|
||||||
*
|
*
|
||||||
|
@ -174,7 +222,14 @@ public final class LaxMalloc {
|
||||||
if((prevChunkSize & 0x80000000) == 0) {
|
if((prevChunkSize & 0x80000000) == 0) {
|
||||||
// previous chunk is not in use, merge!
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,10 +240,21 @@ public final class LaxMalloc {
|
||||||
if((nextChunkSize & 0x80000000) == 0) {
|
if((nextChunkSize & 0x80000000) == 0) {
|
||||||
// next chunk is not in use, merge!
|
// next chunk is not in use, merge!
|
||||||
|
|
||||||
//TODO
|
// remove the next chunk from its list
|
||||||
|
unlinkChunkFromFreeList(nextChunkPtr, nextChunkSize);
|
||||||
|
|
||||||
|
// 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
|
int bucket = getListBucket(chunkSize - 8); // size - 2 ints
|
||||||
|
|
||||||
long bucketMask = Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
long bucketMask = Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
||||||
|
@ -211,7 +277,53 @@ public final class LaxMalloc {
|
||||||
writeChunkPrevFreeAddr(chunkPtr, Address.fromInt(0));
|
writeChunkPrevFreeAddr(chunkPtr, Address.fromInt(0));
|
||||||
bucketStartAddr.putAddress(chunkPtr);
|
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;
|
private static final int NUM_FREE_BUCKETS = 64;
|
||||||
|
@ -224,7 +336,7 @@ public final class LaxMalloc {
|
||||||
if (allocSize < 128)
|
if (allocSize < 128)
|
||||||
return (allocSize >> 3) - 1;
|
return (allocSize >> 3) - 1;
|
||||||
|
|
||||||
int clz = Integer.numberOfLeadingZeros(allocSize);
|
int clz = numberOfLeadingZerosI(allocSize);
|
||||||
int bucketIndex = (clz > 19) ? 110 - (clz << 2) + ((allocSize >> (29 - clz)) ^ 4)
|
int bucketIndex = (clz > 19) ? 110 - (clz << 2) + ((allocSize >> (29 - clz)) ^ 4)
|
||||||
: min(71 - (clz << 1) + ((allocSize >> (30 - clz)) ^ 2), NUM_FREE_BUCKETS - 1);
|
: 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;
|
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