mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
Work on intrinsics
This commit is contained in:
parent
f62a80a1d8
commit
5c25eac049
|
@ -47,6 +47,7 @@ import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsics;
|
||||||
import org.teavm.backend.wasm.model.WasmCustomSection;
|
import org.teavm.backend.wasm.model.WasmCustomSection;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmLocal;
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmMemorySegment;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
import org.teavm.backend.wasm.model.WasmTag;
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
@ -99,6 +100,9 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||||
private List<WasmGCCustomGeneratorFactory> customGeneratorFactories = new ArrayList<>();
|
private List<WasmGCCustomGeneratorFactory> customGeneratorFactories = new ArrayList<>();
|
||||||
private EntryPointTransformation entryPointTransformation = new EntryPointTransformation();
|
private EntryPointTransformation entryPointTransformation = new EntryPointTransformation();
|
||||||
private List<WasmGCClassConsumer> classConsumers = new ArrayList<>();
|
private List<WasmGCClassConsumer> classConsumers = new ArrayList<>();
|
||||||
|
private boolean enableDirectMallocSupport = false;
|
||||||
|
private int directMallocMinHeapSize = 0x10000;
|
||||||
|
private int directMallocMaxHeapSize = 0x10000000;
|
||||||
|
|
||||||
public void setObfuscated(boolean obfuscated) {
|
public void setObfuscated(boolean obfuscated) {
|
||||||
this.obfuscated = obfuscated;
|
this.obfuscated = obfuscated;
|
||||||
|
@ -128,6 +132,18 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||||
this.sourceMapLocation = sourceMapLocation;
|
this.sourceMapLocation = sourceMapLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setEnableDirectMallocSupport(boolean enable) {
|
||||||
|
this.enableDirectMallocSupport = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectMallocMinHeapSize(int minHeapSize) {
|
||||||
|
this.directMallocMinHeapSize = WasmRuntime.align(minHeapSize, WasmHeap.PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectMallocMaxHeapSize(int maxHeapSize) {
|
||||||
|
this.directMallocMaxHeapSize = WasmRuntime.align(maxHeapSize, WasmHeap.PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addIntrinsicFactory(WasmGCIntrinsicFactory intrinsicFactory) {
|
public void addIntrinsicFactory(WasmGCIntrinsicFactory intrinsicFactory) {
|
||||||
intrinsicFactories.add(intrinsicFactory);
|
intrinsicFactories.add(intrinsicFactory);
|
||||||
|
@ -194,6 +210,9 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||||
var deps = new WasmGCDependencies(dependencyAnalyzer);
|
var deps = new WasmGCDependencies(dependencyAnalyzer);
|
||||||
deps.contribute();
|
deps.contribute();
|
||||||
deps.contributeStandardExports();
|
deps.contributeStandardExports();
|
||||||
|
if(enableDirectMallocSupport) {
|
||||||
|
deps.contributeDirectMalloc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -285,6 +304,17 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||||
moduleGenerator.generate();
|
moduleGenerator.generate();
|
||||||
customGenerators.contributeToModule(module);
|
customGenerators.contributeToModule(module);
|
||||||
generateExceptionExports(declarationsGenerator);
|
generateExceptionExports(declarationsGenerator);
|
||||||
|
if(enableDirectMallocSupport) {
|
||||||
|
var heapSegment = new WasmMemorySegment();
|
||||||
|
if (!module.getSegments().isEmpty()) {
|
||||||
|
var lastSegment = module.getSegments().get(module.getSegments().size() - 1);
|
||||||
|
heapSegment.setOffset(WasmRuntime.align(lastSegment.getOffset() + lastSegment.getLength(), WasmHeap.PAGE_SIZE));
|
||||||
|
}
|
||||||
|
heapSegment.setLength(directMallocMinHeapSize);
|
||||||
|
module.getSegments().add(heapSegment);
|
||||||
|
intrinsics.setupLaxMallocHeap(heapSegment.getOffset(), heapSegment.getOffset() + directMallocMinHeapSize,
|
||||||
|
heapSegment.getOffset() + directMallocMaxHeapSize);
|
||||||
|
}
|
||||||
adjustModuleMemory(module);
|
adjustModuleMemory(module);
|
||||||
|
|
||||||
emitWasmFile(module, buildTarget, outputName, debugInfoBuilder);
|
emitWasmFile(module, buildTarget, outputName, debugInfoBuilder);
|
||||||
|
@ -390,9 +420,16 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pages = (memorySize - 1) / WasmHeap.PAGE_SIZE + 1;
|
if(enableDirectMallocSupport) {
|
||||||
module.setMinMemorySize(pages);
|
var minPages = (memorySize - 1) / WasmHeap.PAGE_SIZE + 1;
|
||||||
module.setMaxMemorySize(pages);
|
var maxPages = (memorySize - directMallocMinHeapSize + directMallocMaxHeapSize - 1) / WasmHeap.PAGE_SIZE + 1;
|
||||||
|
module.setMinMemorySize(minPages);
|
||||||
|
module.setMaxMemorySize(maxPages);
|
||||||
|
}else {
|
||||||
|
var pages = (memorySize - 1) / WasmHeap.PAGE_SIZE + 1;
|
||||||
|
module.setMinMemorySize(pages);
|
||||||
|
module.setMaxMemorySize(pages);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void emitWasmFile(WasmModule module, BuildTarget buildTarget, String outputName,
|
private void emitWasmFile(WasmModule module, BuildTarget buildTarget, String outputName,
|
||||||
|
|
|
@ -22,7 +22,9 @@ import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.dependency.AbstractDependencyListener;
|
import org.teavm.dependency.AbstractDependencyListener;
|
||||||
import org.teavm.dependency.DependencyAgent;
|
import org.teavm.dependency.DependencyAgent;
|
||||||
import org.teavm.dependency.DependencyAnalyzer;
|
import org.teavm.dependency.DependencyAnalyzer;
|
||||||
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.runtime.LaxMalloc;
|
||||||
|
|
||||||
public class WasmGCDependencies {
|
public class WasmGCDependencies {
|
||||||
private DependencyAnalyzer analyzer;
|
private DependencyAnalyzer analyzer;
|
||||||
|
@ -127,4 +129,10 @@ public class WasmGCDependencies {
|
||||||
private void contributeString() {
|
private void contributeString() {
|
||||||
analyzer.addDependencyListener(new StringInternDependencySupport());
|
analyzer.addDependencyListener(new StringInternDependencySupport());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void contributeDirectMalloc() {
|
||||||
|
analyzer.linkMethod(new MethodReference(LaxMalloc.class, "laxMalloc", int.class, Address.class)).use();
|
||||||
|
analyzer.linkMethod(new MethodReference(LaxMalloc.class, "laxCalloc", int.class, Address.class)).use();
|
||||||
|
analyzer.linkMethod(new MethodReference(LaxMalloc.class, "laxFree", Address.class, void.class)).use();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 lax1dude.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.intrinsics.gc;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmMemoryGrow;
|
||||||
|
|
||||||
|
public class LaxMallocIntrinsic implements WasmGCIntrinsic {
|
||||||
|
|
||||||
|
private final List<LaxMallocHeapMapper> addressList = new ArrayList<>();
|
||||||
|
private final List<WasmInt32Constant> minAddrConstants = new ArrayList<>();
|
||||||
|
private final List<WasmInt32Constant> maxAddrConstants = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "addrHeap": {
|
||||||
|
WasmExpression value = context.generate(invocation.getArguments().get(0));
|
||||||
|
if(value instanceof WasmInt32Constant) {
|
||||||
|
// if addrHeap is passed a constant i32, add the heap offset at compile time
|
||||||
|
final int memOffset = ((WasmInt32Constant)value).getValue();
|
||||||
|
WasmInt32Constant ret = new WasmInt32Constant(0);
|
||||||
|
addressList.add((heapLoc) -> {
|
||||||
|
ret.setValue(heapLoc + memOffset);
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}else {
|
||||||
|
WasmInt32Constant heapLocConst = new WasmInt32Constant(0);
|
||||||
|
WasmExpression calcOffset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, heapLocConst, value);
|
||||||
|
addressList.add(heapLocConst::setValue);
|
||||||
|
return calcOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "growHeapOuter": {
|
||||||
|
return new WasmMemoryGrow(context.generate(invocation.getArguments().get(0)));
|
||||||
|
}
|
||||||
|
case "getHeapMinAddr": {
|
||||||
|
WasmInt32Constant ret = new WasmInt32Constant(0);
|
||||||
|
minAddrConstants.add(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case "getHeapMaxAddr": {
|
||||||
|
WasmInt32Constant ret = new WasmInt32Constant(0);
|
||||||
|
maxAddrConstants.add(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeapLocation(int heapLoc) {
|
||||||
|
for(LaxMallocHeapMapper mapper : addressList) {
|
||||||
|
mapper.setHeapLocation(heapLoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static interface LaxMallocHeapMapper {
|
||||||
|
void setHeapLocation(int heapLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeapMinAddr(int heapSegmentMinAddr) {
|
||||||
|
for(WasmInt32Constant ct : minAddrConstants) {
|
||||||
|
ct.setValue(heapSegmentMinAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeapMaxAddr(int heapSegmentMaxAddr) {
|
||||||
|
for(WasmInt32Constant ct : maxAddrConstants) {
|
||||||
|
ct.setValue(heapSegmentMaxAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -30,12 +30,14 @@ import org.teavm.interop.DirectMalloc;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.runtime.LaxMalloc;
|
||||||
|
|
||||||
public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
private Map<MethodReference, IntrinsicContainer> intrinsics = new HashMap<>();
|
private Map<MethodReference, IntrinsicContainer> intrinsics = new HashMap<>();
|
||||||
private List<WasmGCIntrinsicFactory> factories;
|
private List<WasmGCIntrinsicFactory> factories;
|
||||||
private ClassReaderSource classes;
|
private ClassReaderSource classes;
|
||||||
private ServiceRepository services;
|
private ServiceRepository services;
|
||||||
|
private LaxMallocIntrinsic laxMallocIntrinsic;
|
||||||
|
|
||||||
public WasmGCIntrinsics(ClassReaderSource classes, ServiceRepository services,
|
public WasmGCIntrinsics(ClassReaderSource classes, ServiceRepository services,
|
||||||
List<WasmGCIntrinsicFactory> factories, Map<MethodReference, WasmGCIntrinsic> customIntrinsics) {
|
List<WasmGCIntrinsicFactory> factories, Map<MethodReference, WasmGCIntrinsic> customIntrinsics) {
|
||||||
|
@ -54,6 +56,7 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
fillString();
|
fillString();
|
||||||
fillResources();
|
fillResources();
|
||||||
fillDirectMalloc();
|
fillDirectMalloc();
|
||||||
|
fillLaxMalloc();
|
||||||
fillAddress();
|
fillAddress();
|
||||||
for (var entry : customIntrinsics.entrySet()) {
|
for (var entry : customIntrinsics.entrySet()) {
|
||||||
add(entry.getKey(), entry.getValue());
|
add(entry.getKey(), entry.getValue());
|
||||||
|
@ -180,6 +183,15 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
add(new MethodReference(DirectMalloc.class, "zmemset", Address.class, int.class, void.class), intrinsic);
|
add(new MethodReference(DirectMalloc.class, "zmemset", Address.class, int.class, void.class), intrinsic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillLaxMalloc() {
|
||||||
|
laxMallocIntrinsic = new LaxMallocIntrinsic();
|
||||||
|
add(new MethodReference(LaxMalloc.class, "laxMalloc", int.class, Address.class), laxMallocIntrinsic);
|
||||||
|
add(new MethodReference(LaxMalloc.class, "laxCalloc", int.class, Address.class), laxMallocIntrinsic);
|
||||||
|
add(new MethodReference(LaxMalloc.class, "laxFree", Address.class, void.class), laxMallocIntrinsic);
|
||||||
|
add(new MethodReference(LaxMalloc.class, "getHeapMinSize", int.class), laxMallocIntrinsic);
|
||||||
|
add(new MethodReference(LaxMalloc.class, "getHeapMaxSize", int.class), laxMallocIntrinsic);
|
||||||
|
}
|
||||||
|
|
||||||
private void fillAddress() {
|
private void fillAddress() {
|
||||||
var intrinsic = new AddressIntrinsic();
|
var intrinsic = new AddressIntrinsic();
|
||||||
add(new MethodReference(Address.class, "add", int.class, Address.class), intrinsic);
|
add(new MethodReference(Address.class, "add", int.class, Address.class), intrinsic);
|
||||||
|
@ -233,6 +245,12 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
return result.intrinsic;
|
return result.intrinsic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setupLaxMallocHeap(int heapAddr, int heapSegmentMinAddr, int heapSegmentMaxAddr) {
|
||||||
|
laxMallocIntrinsic.setHeapLocation(heapAddr);
|
||||||
|
laxMallocIntrinsic.setHeapMinAddr(heapSegmentMinAddr);
|
||||||
|
laxMallocIntrinsic.setHeapMaxAddr(heapSegmentMaxAddr);
|
||||||
|
}
|
||||||
|
|
||||||
static class IntrinsicContainer {
|
static class IntrinsicContainer {
|
||||||
final WasmGCIntrinsic intrinsic;
|
final WasmGCIntrinsic intrinsic;
|
||||||
|
|
||||||
|
|
|
@ -50,12 +50,23 @@ 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
|
||||||
|
|
||||||
|
private static native Address addrHeap(int offset); // Intrinsic function to get an address in the heap segment
|
||||||
|
|
||||||
|
private static native int growHeapOuter(int bytes); // Intrinsic function to grow the heap segment
|
||||||
|
|
||||||
|
private static native Address getHeapMinAddr(); // Intrinsic function to get the minimum direct malloc heap segment ending address
|
||||||
|
|
||||||
|
private static native Address getHeapMaxAddr(); // Intrinsic function to get the maximum direct malloc heap segment ending address
|
||||||
|
|
||||||
|
@Import(name = "teavm_notifyHeapResized")
|
||||||
|
private static native void notifyHeapResized();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// zero out the control region
|
// zero out the control region
|
||||||
DirectMalloc.zmemset(Address.fromInt(0), ADDR_HEAP_DATA_START);
|
DirectMalloc.zmemset(addrHeap(0), ADDR_HEAP_DATA_START);
|
||||||
// initialize heap limit
|
// initialize heap limit
|
||||||
Address.fromInt(ADDR_HEAP_INNER_LIMIT).putInt(ADDR_HEAP_DATA_START);
|
addrHeap(ADDR_HEAP_INNER_LIMIT).putAddress(addrHeap(ADDR_HEAP_DATA_START));
|
||||||
Address.fromInt(ADDR_HEAP_OUTER_LIMIT).putInt(0x10000);
|
addrHeap(ADDR_HEAP_OUTER_LIMIT).putAddress(getHeapMinAddr());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,7 +107,7 @@ public final class LaxMalloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// load bitmask of buckets with free chunks
|
// load bitmask of buckets with free chunks
|
||||||
long bucketMask = Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
long bucketMask = addrHeap(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
||||||
|
|
||||||
// mask away the buckets that we know are too small for this allocation
|
// mask away the buckets that we know are too small for this allocation
|
||||||
bucketMask = (bucketMask & (0xFFFFFFFFFFFFFFFFL << bucket));
|
bucketMask = (bucketMask & (0xFFFFFFFFFFFFFFFFL << bucket));
|
||||||
|
@ -125,7 +136,7 @@ public final class LaxMalloc {
|
||||||
// quickly determine which bucket it is with bit hacks
|
// quickly determine which bucket it is with bit hacks
|
||||||
int availableBucket = Long.numberOfTrailingZeros(bucketMask);
|
int availableBucket = Long.numberOfTrailingZeros(bucketMask);
|
||||||
|
|
||||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(availableBucket << SIZEOF_PTR_SH);
|
Address bucketStartAddr = addrHeap(ADDR_HEAP_BUCKETS_START).add(availableBucket << SIZEOF_PTR_SH);
|
||||||
Address chunkPtr = bucketStartAddr.getAddress();
|
Address chunkPtr = bucketStartAddr.getAddress();
|
||||||
int chunkSize = readChunkSizeStatus(chunkPtr);
|
int chunkSize = readChunkSizeStatus(chunkPtr);
|
||||||
Address itrChunkStart = Address.fromInt(0);
|
Address itrChunkStart = Address.fromInt(0);
|
||||||
|
@ -149,7 +160,7 @@ public final class LaxMalloc {
|
||||||
if(bucketMask != 0l) {
|
if(bucketMask != 0l) {
|
||||||
// there is a bucket with a larger chunk
|
// there is a bucket with a larger chunk
|
||||||
int availableLargerBucket = Long.numberOfTrailingZeros(bucketMask);
|
int availableLargerBucket = Long.numberOfTrailingZeros(bucketMask);
|
||||||
Address largerBucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(availableLargerBucket << SIZEOF_PTR_SH);
|
Address largerBucketStartAddr = addrHeap(ADDR_HEAP_BUCKETS_START).add(availableLargerBucket << SIZEOF_PTR_SH);
|
||||||
Address largerChunkPtr = largerBucketStartAddr.getAddress();
|
Address largerChunkPtr = largerBucketStartAddr.getAddress();
|
||||||
int largerChunkSize = readChunkSizeStatus(largerChunkPtr);
|
int largerChunkSize = readChunkSizeStatus(largerChunkPtr);
|
||||||
|
|
||||||
|
@ -234,10 +245,10 @@ public final class LaxMalloc {
|
||||||
private static Address laxHugeAlloc(int sizeBytes, boolean cleared) {
|
private static Address laxHugeAlloc(int sizeBytes, boolean cleared) {
|
||||||
|
|
||||||
// check the bucket mask if bucket 63 has any chunks
|
// check the bucket mask if bucket 63 has any chunks
|
||||||
if((Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong() & 0x8000000000000000L) != 0) {
|
if((addrHeap(ADDR_HEAP_BUCKETS_FREE_MASK).getLong() & 0x8000000000000000L) != 0) {
|
||||||
|
|
||||||
// bucket 63 address
|
// bucket 63 address
|
||||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(63 << SIZEOF_PTR_SH);
|
Address bucketStartAddr = addrHeap(ADDR_HEAP_BUCKETS_START).add(63 << SIZEOF_PTR_SH);
|
||||||
Address chunkPtr = bucketStartAddr.getAddress();
|
Address chunkPtr = bucketStartAddr.getAddress();
|
||||||
|
|
||||||
// iterate all free huge chunks
|
// iterate all free huge chunks
|
||||||
|
@ -302,7 +313,7 @@ public final class LaxMalloc {
|
||||||
// set the chunk no longer in use
|
// set the chunk no longer in use
|
||||||
chunkSize &= 0x7FFFFFFF;
|
chunkSize &= 0x7FFFFFFF;
|
||||||
|
|
||||||
if(Address.fromInt(ADDR_HEAP_DATA_START).isLessThan(chunkPtr)) {
|
if(addrHeap(ADDR_HEAP_DATA_START).isLessThan(chunkPtr)) {
|
||||||
// check if we can merge with the previous chunk, and move it to another bucket
|
// check if we can merge with the previous chunk, and move it to another bucket
|
||||||
Address prevChunkPtr = chunkPtr.add(-(chunkPtr.add(-4).getInt()));
|
Address prevChunkPtr = chunkPtr.add(-(chunkPtr.add(-4).getInt()));
|
||||||
int prevChunkSize = readChunkSizeStatus(prevChunkPtr);
|
int prevChunkSize = readChunkSizeStatus(prevChunkPtr);
|
||||||
|
@ -320,7 +331,7 @@ public final class LaxMalloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
Address nextChunkPtr = chunkPtr.add(chunkSize);
|
Address nextChunkPtr = chunkPtr.add(chunkSize);
|
||||||
if(Address.fromInt(ADDR_HEAP_INNER_LIMIT).getAddress().isLessThan(nextChunkPtr)) {
|
if(addrHeap(ADDR_HEAP_INNER_LIMIT).getAddress().isLessThan(nextChunkPtr)) {
|
||||||
// check if we can merge with the next chunk as well
|
// check if we can merge with the next chunk as well
|
||||||
int nextChunkSize = readChunkSizeStatus(nextChunkPtr);
|
int nextChunkSize = readChunkSizeStatus(nextChunkPtr);
|
||||||
if((nextChunkSize & 0x80000000) == 0) {
|
if((nextChunkSize & 0x80000000) == 0) {
|
||||||
|
@ -388,8 +399,8 @@ public final class LaxMalloc {
|
||||||
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
|
||||||
|
|
||||||
long bucketMask = Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
long bucketMask = addrHeap(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
||||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(bucket << SIZEOF_PTR_SH);
|
Address bucketStartAddr = addrHeap(ADDR_HEAP_BUCKETS_START).add(bucket << SIZEOF_PTR_SH);
|
||||||
|
|
||||||
// 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) {
|
||||||
|
@ -401,7 +412,7 @@ public final class LaxMalloc {
|
||||||
|
|
||||||
// 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);
|
addrHeap(ADDR_HEAP_BUCKETS_FREE_MASK).putLong(bucketMask);
|
||||||
|
|
||||||
}else {
|
}else {
|
||||||
|
|
||||||
|
@ -434,13 +445,13 @@ public final class LaxMalloc {
|
||||||
|
|
||||||
int chunkBucket = getListBucket(chunkSize - 8); // size - 2 ints
|
int chunkBucket = getListBucket(chunkSize - 8); // size - 2 ints
|
||||||
|
|
||||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(chunkBucket << SIZEOF_PTR_SH);
|
Address bucketStartAddr = addrHeap(ADDR_HEAP_BUCKETS_START).add(chunkBucket << SIZEOF_PTR_SH);
|
||||||
bucketStartAddr.putAddress(Address.fromInt(0)); // remove chunk from the bucket
|
bucketStartAddr.putAddress(Address.fromInt(0)); // remove chunk from the bucket
|
||||||
|
|
||||||
// clear the bit in the free buckets bitmask
|
// clear the bit in the free buckets bitmask
|
||||||
long bucketsFreeMask = Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
long bucketsFreeMask = addrHeap(ADDR_HEAP_BUCKETS_FREE_MASK).getLong();
|
||||||
bucketsFreeMask &= ~(1L << chunkBucket);
|
bucketsFreeMask &= ~(1L << chunkBucket);
|
||||||
Address.fromInt(ADDR_HEAP_BUCKETS_FREE_MASK).putLong(bucketsFreeMask);
|
addrHeap(ADDR_HEAP_BUCKETS_FREE_MASK).putLong(bucketsFreeMask);
|
||||||
|
|
||||||
}else {
|
}else {
|
||||||
// there are other chunks in this bucket
|
// there are other chunks in this bucket
|
||||||
|
@ -450,7 +461,7 @@ public final class LaxMalloc {
|
||||||
writeChunkPrevFreeAddr(nextChunkPtr, prevChunkPtr);
|
writeChunkPrevFreeAddr(nextChunkPtr, prevChunkPtr);
|
||||||
|
|
||||||
int chunkBucket = getListBucket(chunkSize - 8); // size - 2 ints
|
int chunkBucket = getListBucket(chunkSize - 8); // size - 2 ints
|
||||||
Address bucketStartAddr = Address.fromInt(ADDR_HEAP_BUCKETS_START).add(chunkBucket << SIZEOF_PTR_SH);
|
Address bucketStartAddr = addrHeap(ADDR_HEAP_BUCKETS_START).add(chunkBucket << SIZEOF_PTR_SH);
|
||||||
Address bucketStartChunk = bucketStartAddr.getAddress();
|
Address bucketStartChunk = bucketStartAddr.getAddress();
|
||||||
|
|
||||||
// chunk is the first in the bucket, so we also need to
|
// chunk is the first in the bucket, so we also need to
|
||||||
|
@ -480,28 +491,27 @@ public final class LaxMalloc {
|
||||||
* This is our sbrk
|
* This is our sbrk
|
||||||
*/
|
*/
|
||||||
private static Address growHeap(int amount) {
|
private static Address growHeap(int amount) {
|
||||||
Address heapInnerLimit = Address.fromInt(ADDR_HEAP_INNER_LIMIT).getAddress();
|
Address heapInnerLimit = addrHeap(ADDR_HEAP_INNER_LIMIT).getAddress();
|
||||||
Address heapOuterLimit = Address.fromInt(ADDR_HEAP_OUTER_LIMIT).getAddress();
|
Address heapOuterLimit = addrHeap(ADDR_HEAP_OUTER_LIMIT).getAddress();
|
||||||
Address newHeapInnerLimit = heapInnerLimit.add(amount);
|
Address newHeapInnerLimit = heapInnerLimit.add(amount);
|
||||||
if(heapOuterLimit.isLessThan(newHeapInnerLimit)) {
|
if(heapOuterLimit.isLessThan(newHeapInnerLimit)) {
|
||||||
int bytesNeeded = newHeapInnerLimit.toInt() - heapOuterLimit.toInt();
|
int bytesNeeded = newHeapInnerLimit.toInt() - heapOuterLimit.toInt();
|
||||||
bytesNeeded = (bytesNeeded + 0xFFFF) & 0xFFFF0000;
|
bytesNeeded = (bytesNeeded + 0xFFFF) & 0xFFFF0000;
|
||||||
if(growHeapOuter(bytesNeeded)) {
|
Address newHeapOuterLimit = heapOuterLimit.add(bytesNeeded);
|
||||||
Address.fromInt(ADDR_HEAP_INNER_LIMIT).putAddress(newHeapInnerLimit);
|
if(!getHeapMaxAddr().isLessThan(newHeapOuterLimit) && growHeapOuter(bytesNeeded >> 16) != -1) {
|
||||||
Address.fromInt(ADDR_HEAP_OUTER_LIMIT).putAddress(heapOuterLimit.add(bytesNeeded));
|
addrHeap(ADDR_HEAP_INNER_LIMIT).putAddress(newHeapInnerLimit);
|
||||||
|
addrHeap(ADDR_HEAP_OUTER_LIMIT).putAddress(newHeapOuterLimit);
|
||||||
|
notifyHeapResized();
|
||||||
return newHeapInnerLimit;
|
return newHeapInnerLimit;
|
||||||
}else {
|
}else {
|
||||||
return Address.fromInt(0);
|
return Address.fromInt(0);
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
Address.fromInt(ADDR_HEAP_INNER_LIMIT).putAddress(newHeapInnerLimit);
|
addrHeap(ADDR_HEAP_INNER_LIMIT).putAddress(newHeapInnerLimit);
|
||||||
return newHeapInnerLimit;
|
return newHeapInnerLimit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Import(name = "teavm_growHeap")
|
|
||||||
private static native boolean growHeapOuter(int bytes);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note that on a free chunk, this is the size, because the status bit is 0
|
* Note that on a free chunk, this is the size, because the status bit is 0
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue
Block a user