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
2b73f658d0
commit
5830392f60
|
@ -84,52 +84,74 @@ public final class LaxMalloc {
|
||||||
|
|
||||||
if(bucket == 63) {
|
if(bucket == 63) {
|
||||||
// special bucket for the huge allocations
|
// special bucket for the huge allocations
|
||||||
// uses a different function
|
// uses a different slower function
|
||||||
return laxHugeAlloc(sizeBytes, cleared);
|
return laxHugeAlloc(sizeBytes, cleared);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load bitmask of buckets with free chunks
|
||||||
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
|
// mask away the buckets that we know are too small for this allocation
|
||||||
if((bucketMask & (1L << bucket)) == 0l) {
|
bucketMask = (bucketMask & (0xFFFFFFFFFFFFFFFFL << bucket));
|
||||||
// no more free chunks, let us first check if there are any
|
|
||||||
// chunks in the larger buckets we can split
|
// there are no more buckets with free chunks
|
||||||
long largerBucketsMask = (bucketMask & (0xFFFFFFFFFFFFFFFFL << (bucket + 1)));
|
// need to sbrk
|
||||||
if(largerBucketsMask != 0l) {
|
if(bucketMask == 0l) {
|
||||||
// at least one larger chunk exists
|
int sizePlusInts = sizeBytes + 8; // size + 2 ints
|
||||||
// we can quickly find it using the bitmask
|
Address newChunk = growHeap(sizePlusInts); // sbrk
|
||||||
int largerBucket = numberOfTrailingZerosL(largerBucketsMask);
|
|
||||||
|
// Out of memory
|
||||||
|
if(newChunk.toInt() == 0) {
|
||||||
|
return Address.fromInt(0); //TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// provision the new chunk
|
||||||
|
newChunk.putInt(sizePlusInts | 0x80000000); // size + in use flag
|
||||||
|
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 memory
|
||||||
|
return newChunk.add(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// at least one bucket exists containing a free chunk,
|
||||||
|
// quickly determine which bucket it is with bit hacks
|
||||||
|
int availableBucket = numberOfTrailingZerosL(bucketMask);
|
||||||
|
|
||||||
|
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(availableBucket << SIZEOF_PTR_SH);
|
||||||
|
Address chunkPtr = bucketStartAddr.getAddress();
|
||||||
|
int chunkSize = readChunkSize(chunkPtr);
|
||||||
|
boolean bucketHasMultipleChunks = false;
|
||||||
|
|
||||||
|
// check if the first chunk in the bucket is large enough
|
||||||
|
if(chunkSize - 8 < sizeBytes) { // size - 2 ints
|
||||||
|
|
||||||
|
// the chunk is not large enough, move the first chunk to the end of the list
|
||||||
|
// and then check in the next bucket (where the chunks are definitely large enough)
|
||||||
|
// this functionality is present in emmalloc (emscripten)
|
||||||
|
|
||||||
|
Address chunkNextPtr = readChunkNextFreeAddr(chunkPtr);
|
||||||
|
if(chunkNextPtr.getInt() != chunkPtr.getInt()) {
|
||||||
|
bucketStartAddr.putAddress(chunkNextPtr);
|
||||||
|
chunkPtr = chunkNextPtr;
|
||||||
|
bucketHasMultipleChunks = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extend mask to the next bucket
|
||||||
|
bucketMask = (bucketMask & (0xFFFFFFFFFFFFFFFFL << (bucket + 1)));
|
||||||
|
|
||||||
|
if(bucketMask != 0l) {
|
||||||
|
// there is a bucket with a larger chunk
|
||||||
|
int availableLargerBucket = numberOfTrailingZerosL(bucketMask);
|
||||||
|
Address largerBucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(availableLargerBucket << SIZEOF_PTR_SH);
|
||||||
|
Address largerChunkPtr = largerBucketStartAddr.getAddress();
|
||||||
|
int largerChunkSize = readChunkSize(largerChunkPtr);
|
||||||
|
|
||||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(largerBucket << SIZEOF_PTR_SH);
|
// this will remove the chunk from the free list
|
||||||
Address chunkPtr = bucketStartAddr.getAddress();
|
allocateMemoryFromChunk(largerChunkPtr, largerChunkSize, sizeBytes);
|
||||||
int chunkSize = readChunkSize(chunkPtr);
|
|
||||||
|
|
||||||
int chunkNewSize = chunkSize - sizeBytes - 8; // -size - 2 ints - 2 more ints
|
// +4 bytes to skip size int
|
||||||
|
Address ret = largerChunkPtr.add(4);
|
||||||
// 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
|
// clear if requested
|
||||||
if(cleared) {
|
if(cleared) {
|
||||||
|
@ -137,50 +159,13 @@ public final class LaxMalloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}else {
|
|
||||||
// No larger chunks already exist that we can split,
|
|
||||||
// time to sbrk
|
|
||||||
int sizePlusInts = sizeBytes + 8; // size + 2 ints
|
|
||||||
Address newChunk = growHeap(sizePlusInts);
|
|
||||||
|
|
||||||
// Out of memory
|
|
||||||
if(newChunk.toInt() == 0) {
|
|
||||||
return Address.fromInt(0); //TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
// provision the new chunk
|
|
||||||
newChunk.putInt(sizePlusInts | 0x80000000); // size + in use flag
|
|
||||||
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 memory
|
|
||||||
return newChunk.add(4);
|
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
// At least one free chunk is available, get it from the bucket
|
// the first chunk in the bucket is large enough
|
||||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(bucket << SIZEOF_PTR_SH);
|
// this will remove the chunk from the free list
|
||||||
Address chunkPtr = bucketStartAddr.getAddress();
|
allocateMemoryFromChunk(chunkPtr, chunkSize, sizeBytes);
|
||||||
|
|
||||||
Address nextStart = readChunkNextFreeAddr(chunkPtr);
|
// +4 bytes to skip size int
|
||||||
if(nextStart.toInt() != 0) {
|
|
||||||
// there is another free chunk in the bucket that comes after this chunk,
|
|
||||||
// make the next free chunk in the list the first free chunk
|
|
||||||
bucketStartAddr.putAddress(nextStart);
|
|
||||||
writeChunkPrevFreeAddr(nextStart, Address.fromInt(0));
|
|
||||||
}else {
|
|
||||||
// there are no remaining free chunks in the bucket
|
|
||||||
// clear the bit in the bucket bitmask
|
|
||||||
bucketMask = (bucketMask ^ (1L << bucket));
|
|
||||||
Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).putLong(bucketMask);
|
|
||||||
|
|
||||||
// set bucket start chunk pointer to null
|
|
||||||
bucketStartAddr.putAddress(Address.fromInt(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark the chunk in use
|
|
||||||
setChunkInUse(chunkPtr, true);
|
|
||||||
|
|
||||||
// return the chunk we just removed from the list, +4 bytes to skip size
|
|
||||||
Address ret = chunkPtr.add(4);
|
Address ret = chunkPtr.add(4);
|
||||||
|
|
||||||
// clear if requested
|
// clear if requested
|
||||||
|
@ -190,10 +175,105 @@ public final class LaxMalloc {
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(bucketHasMultipleChunks) {
|
||||||
|
|
||||||
|
// if we've reached this point, it means the first chunk in the bucket wasn't large enough
|
||||||
|
// and there weren't any chunks in the larger buckets we could split up
|
||||||
|
// so we need to look closer
|
||||||
|
|
||||||
|
// iterate the (only) bucket of possibly large enough chunks
|
||||||
|
Address addrIterator = chunkPtr;
|
||||||
|
while((addrIterator = readChunkNextFreeAddr(addrIterator)).getInt() != chunkPtr.getInt()) {
|
||||||
|
chunkSize = readChunkSize(addrIterator);
|
||||||
|
|
||||||
|
// check if the chunk is large enough
|
||||||
|
if(chunkSize - 8 >= sizeBytes) { // size - 2 ints
|
||||||
|
// we've found a large enough chunk
|
||||||
|
// this will remove the chunk from the free list
|
||||||
|
allocateMemoryFromChunk(addrIterator, chunkSize, sizeBytes);
|
||||||
|
|
||||||
|
// +4 bytes to skip size int
|
||||||
|
Address ret = chunkPtr.add(4);
|
||||||
|
|
||||||
|
// clear if requested
|
||||||
|
if(cleared) {
|
||||||
|
Allocator.fillZero(ret, sizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no other options, time to sbrk
|
||||||
|
|
||||||
|
int sizePlusInts = sizeBytes + 8; // size + 2 ints
|
||||||
|
Address newChunk = growHeap(sizePlusInts); // sbrk
|
||||||
|
|
||||||
|
// Out of memory
|
||||||
|
if(newChunk.toInt() == 0) {
|
||||||
|
return Address.fromInt(0); //TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// provision the new chunk
|
||||||
|
newChunk.putInt(sizePlusInts | 0x80000000); // size + in use flag
|
||||||
|
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 memory
|
||||||
|
return newChunk.add(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Address laxHugeAlloc(int sizeBytes, boolean cleared) {
|
private static Address laxHugeAlloc(int sizeBytes, boolean cleared) {
|
||||||
return null; //TODO: bucket number 63
|
|
||||||
|
// check the bucket mask if bucket 63 has any chunks
|
||||||
|
if((Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong() & 0x8000000000000000L) != 0) {
|
||||||
|
|
||||||
|
// bucket 63 address
|
||||||
|
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(63 << SIZEOF_PTR_SH);
|
||||||
|
Address chunkPtr = bucketStartAddr.getAddress();
|
||||||
|
|
||||||
|
// iterate all free huge chunks
|
||||||
|
Address addrIterator = chunkPtr;
|
||||||
|
while((addrIterator = readChunkNextFreeAddr(addrIterator)).getInt() != chunkPtr.getInt()) {
|
||||||
|
int chunkSize = readChunkSize(addrIterator);
|
||||||
|
|
||||||
|
if(chunkSize - 8 >= sizeBytes) { // size - 2 ints
|
||||||
|
// we've found a large enough chunk
|
||||||
|
// this will remove the chunk from the free list
|
||||||
|
allocateMemoryFromChunk(addrIterator, chunkSize, sizeBytes);
|
||||||
|
|
||||||
|
// +4 bytes to skip size int
|
||||||
|
Address ret = chunkPtr.add(4);
|
||||||
|
|
||||||
|
// clear if requested
|
||||||
|
if(cleared) {
|
||||||
|
Allocator.fillZero(ret, sizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no free huge chunks found, time to sbrk
|
||||||
|
|
||||||
|
int sizePlusInts = sizeBytes + 8; // size + 2 ints
|
||||||
|
Address newChunk = growHeap(sizePlusInts); // sbrk
|
||||||
|
|
||||||
|
// Out of memory
|
||||||
|
if(newChunk.toInt() == 0) {
|
||||||
|
return Address.fromInt(0); //TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// provision the new chunk
|
||||||
|
newChunk.putInt(sizePlusInts | 0x80000000); // size + in use flag
|
||||||
|
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 memory
|
||||||
|
return newChunk.add(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -229,7 +309,7 @@ public final class LaxMalloc {
|
||||||
chunkPtr = prevChunkPtr;
|
chunkPtr = prevChunkPtr;
|
||||||
chunkSize += prevChunkSize;
|
chunkSize += prevChunkSize;
|
||||||
chunkPtr.putInt(chunkSize);
|
chunkPtr.putInt(chunkSize);
|
||||||
chunkPtr.add(chunkSize).putInt(chunkSize);
|
chunkPtr.add(chunkSize - 4).putInt(chunkSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +326,7 @@ public final class LaxMalloc {
|
||||||
// resize the current chunk to also contain the next chunk
|
// resize the current chunk to also contain the next chunk
|
||||||
chunkSize += nextChunkSize;
|
chunkSize += nextChunkSize;
|
||||||
chunkPtr.putInt(chunkSize);
|
chunkPtr.putInt(chunkSize);
|
||||||
chunkPtr.add(chunkSize).putInt(chunkSize);
|
chunkPtr.add(chunkSize - 4).putInt(chunkSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +334,44 @@ public final class LaxMalloc {
|
||||||
linkChunkInFreeList(chunkPtr, chunkSize);
|
linkChunkInFreeList(chunkPtr, chunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates memory from a free chunk, if the allocSize is smaller than the chunkSize by
|
||||||
|
* enough of a margin then the chunk is split into two smaller chunks, and the upper part
|
||||||
|
* of the chunk is returned to a bucket of free chunks
|
||||||
|
*/
|
||||||
|
private static void allocateMemoryFromChunk(Address chunkPtr, int chunkSize, int allocSize) {
|
||||||
|
// remove the chunk from its bucket
|
||||||
|
unlinkChunkFromFreeList(chunkPtr, chunkSize);
|
||||||
|
|
||||||
|
int otherHalfSize = chunkSize - allocSize - 8; // -size - 2 ints
|
||||||
|
|
||||||
|
// check if we can split the chunk into two smaller chunks
|
||||||
|
// chunk must be large enough to hold the 2 list pointers
|
||||||
|
if(otherHalfSize - (2 << SIZEOF_PTR_SH) >= MIN_ALLOC_SIZE) {
|
||||||
|
// chunk is large enough to split
|
||||||
|
|
||||||
|
// provision the lower part of the chunk, the part we want to use
|
||||||
|
int sizePlusInts = allocSize + 8; // size + 2 ints
|
||||||
|
chunkPtr.putInt(sizePlusInts | 0x80000000); // size + in use flag
|
||||||
|
chunkPtr.add(allocSize + 4).putInt(sizePlusInts); // size integer at the end
|
||||||
|
|
||||||
|
// provision the upper part of the chunk that we want to return to the free list
|
||||||
|
Address otherChunkPtr = chunkPtr.add(sizePlusInts);
|
||||||
|
otherChunkPtr.putInt(otherHalfSize); // size
|
||||||
|
otherChunkPtr.add(otherHalfSize - 4).putInt(otherHalfSize); // size (end)
|
||||||
|
|
||||||
|
// return the upper part of the chunk to the free chunks list
|
||||||
|
linkChunkInFreeList(otherChunkPtr, otherHalfSize);
|
||||||
|
|
||||||
|
}else {
|
||||||
|
// not large enough to split, just take the entire chunk
|
||||||
|
setChunkInUse(chunkPtr, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a free chunk to its corresponding bucket
|
||||||
|
*/
|
||||||
private static void linkChunkInFreeList(Address chunkPtr, int 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
|
||||||
|
|
||||||
|
@ -262,27 +380,43 @@ public final class LaxMalloc {
|
||||||
|
|
||||||
// test the bucket mask if the bucket is empty
|
// test the bucket mask if the bucket is empty
|
||||||
if((bucketMask & (1L << bucket)) == 0l) {
|
if((bucketMask & (1L << bucket)) == 0l) {
|
||||||
|
|
||||||
// bucket is empty, add the free chunk to the list
|
// bucket is empty, add the free chunk to the list
|
||||||
bucketStartAddr.putAddress(chunkPtr);
|
bucketStartAddr.putAddress(chunkPtr);
|
||||||
writeChunkPrevFreeAddr(chunkPtr, Address.fromInt(0));
|
writeChunkPrevFreeAddr(chunkPtr, chunkPtr);
|
||||||
writeChunkNextFreeAddr(chunkPtr, Address.fromInt(0));
|
writeChunkNextFreeAddr(chunkPtr, chunkPtr);
|
||||||
|
|
||||||
// set the free bit in bucket mask
|
// set the free bit in bucket mask
|
||||||
bucketMask |= (1L << bucket);
|
bucketMask |= (1L << bucket);
|
||||||
Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).putLong(bucketMask);
|
Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).putLong(bucketMask);
|
||||||
|
|
||||||
}else {
|
}else {
|
||||||
|
|
||||||
// bucket is not empty, append to the bucket's existing free chunks list
|
// bucket is not empty, append to the bucket's existing free chunks list
|
||||||
Address otherBucketStart = bucketStartAddr.getAddress();
|
Address otherBucketStart = bucketStartAddr.getAddress();
|
||||||
writeChunkPrevFreeAddr(otherBucketStart, chunkPtr);
|
Address otherBucketPrev = readChunkPrevFreeAddr(otherBucketStart);
|
||||||
|
|
||||||
|
// link new chunk to the existing chunks in the bucket
|
||||||
|
writeChunkPrevFreeAddr(chunkPtr, otherBucketPrev);
|
||||||
writeChunkNextFreeAddr(chunkPtr, otherBucketStart);
|
writeChunkNextFreeAddr(chunkPtr, otherBucketStart);
|
||||||
writeChunkPrevFreeAddr(chunkPtr, Address.fromInt(0));
|
|
||||||
|
// link the existing chunks in the bucket to the new chunk
|
||||||
|
writeChunkPrevFreeAddr(otherBucketStart, chunkPtr);
|
||||||
|
writeChunkNextFreeAddr(otherBucketPrev, chunkPtr);
|
||||||
|
|
||||||
|
// put the chunk in the bucket
|
||||||
bucketStartAddr.putAddress(chunkPtr);
|
bucketStartAddr.putAddress(chunkPtr);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a free chunk from its corresponding bucket
|
||||||
|
*/
|
||||||
private static void unlinkChunkFromFreeList(Address chunkPtr, int chunkSize) {
|
private static void unlinkChunkFromFreeList(Address chunkPtr, int chunkSize) {
|
||||||
Address prevChunkPtr = readChunkPrevFreeAddr(chunkPtr);
|
Address prevChunkPtr = readChunkPrevFreeAddr(chunkPtr);
|
||||||
Address nextChunkPtr = readChunkNextFreeAddr(chunkPtr);
|
Address nextChunkPtr = readChunkNextFreeAddr(chunkPtr);
|
||||||
if((prevChunkPtr.toInt() | nextChunkPtr.toInt()) == 0) {
|
if(prevChunkPtr.toInt() == nextChunkPtr.toInt()) {
|
||||||
// chunk is the only one currently in its bucket
|
// chunk is the only one currently in its bucket
|
||||||
|
|
||||||
int chunkBucket = getListBucket(chunkSize - 8); // size - 2 ints
|
int chunkBucket = getListBucket(chunkSize - 8); // size - 2 ints
|
||||||
|
@ -298,36 +432,22 @@ public final class LaxMalloc {
|
||||||
}else {
|
}else {
|
||||||
// there are other chunks in this bucket
|
// there are other chunks in this bucket
|
||||||
|
|
||||||
if(prevChunkPtr.toInt() != 0) {
|
// link the next chunk to the previous chunk
|
||||||
// previous chunk exists
|
writeChunkNextFreeAddr(prevChunkPtr, nextChunkPtr);
|
||||||
|
writeChunkPrevFreeAddr(nextChunkPtr, prevChunkPtr);
|
||||||
if(nextChunkPtr.toInt() != 0) {
|
|
||||||
// next chunk exits, link it to the previous chunk
|
int chunkBucket = getListBucket(chunkSize - 8); // size - 2 ints
|
||||||
writeChunkNextFreeAddr(prevChunkPtr, nextChunkPtr);
|
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(chunkBucket << SIZEOF_PTR_SH);
|
||||||
writeChunkPrevFreeAddr(nextChunkPtr, prevChunkPtr);
|
Address bucketStartChunk = bucketStartAddr.getAddress();
|
||||||
}else {
|
|
||||||
// there is no next chunk
|
// chunk is the first in the bucket, so we also need to
|
||||||
writeChunkNextFreeAddr(prevChunkPtr, Address.fromInt(0));
|
// update the bucket to point to the next chunk instead
|
||||||
}
|
if(bucketStartChunk.toInt() == chunkPtr.toInt()) {
|
||||||
|
|
||||||
}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);
|
bucketStartAddr.putAddress(nextChunkPtr);
|
||||||
|
|
||||||
// unlink the next chunk from the current chunk
|
|
||||||
writeChunkPrevFreeAddr(nextChunkPtr, Address.fromInt(0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int NUM_FREE_BUCKETS = 64;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://github.com/emscripten-core/emscripten/blob/16a0bf174cb85f88b6d9dcc8ee7fbca59390185b/system/lib/emmalloc.c#L241
|
* https://github.com/emscripten-core/emscripten/blob/16a0bf174cb85f88b6d9dcc8ee7fbca59390185b/system/lib/emmalloc.c#L241
|
||||||
* (MIT License)
|
* (MIT License)
|
||||||
|
@ -338,7 +458,7 @@ public final class LaxMalloc {
|
||||||
|
|
||||||
int clz = numberOfLeadingZerosI(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), 63);
|
||||||
|
|
||||||
return bucketIndex;
|
return bucketIndex;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user