DirectMalloc intrinsic

This commit is contained in:
lax1dude 2024-11-01 20:19:37 -07:00
parent acb4caa358
commit 7d8f5fc9c4
3 changed files with 161 additions and 5 deletions

View File

@ -0,0 +1,106 @@
/*
* 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 org.teavm.ast.InvocationExpr;
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
import org.teavm.backend.wasm.model.expression.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmCopy;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmFill;
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
import org.teavm.interop.Address;
import org.teavm.interop.DirectMalloc;
import org.teavm.model.MethodReference;
import org.teavm.runtime.LaxMalloc;
public class DirectMallocIntrinsic implements WasmIntrinsic {
private static final MethodReference LAX_MALLOC = new MethodReference(LaxMalloc.class, "laxMalloc", int.class,
Address.class);
private static final MethodReference LAX_CALLOC = new MethodReference(LaxMalloc.class, "laxCalloc", int.class,
Address.class);
private static final MethodReference LAX_FREE = new MethodReference(LaxMalloc.class, "laxFree", Address.class,
void.class);
@Override
public boolean isApplicable(MethodReference methodReference) {
if (!methodReference.getClassName().equals(DirectMalloc.class.getName())) {
return false;
}
switch (methodReference.getName()) {
case "malloc":
case "calloc":
case "free":
case "memcpy":
case "memset":
case "zmemset":
return true;
default:
return false;
}
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
switch (invocation.getMethod().getName()) {
case "malloc": {
var function = manager.getFunctions().forStaticMethod(LAX_MALLOC);
var call = new WasmCall(function);
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
return call;
}
case "calloc": {
var function = manager.getFunctions().forStaticMethod(LAX_CALLOC);
var call = new WasmCall(function);
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
return call;
}
case "free": {
var function = manager.getFunctions().forStaticMethod(LAX_FREE);
var call = new WasmCall(function);
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
return call;
}
case "memcpy": {
var copy = new WasmCopy();
copy.setDestinationIndex(manager.generate(invocation.getArguments().get(0)));
copy.setSourceIndex(manager.generate(invocation.getArguments().get(1)));
copy.setCount(manager.generate(invocation.getArguments().get(2)));
return copy;
}
case "memset": {
var fill = new WasmFill();
fill.setIndex(manager.generate(invocation.getArguments().get(0)));
fill.setValue(manager.generate(invocation.getArguments().get(1)));
fill.setCount(manager.generate(invocation.getArguments().get(2)));
return fill;
}
case "zmemset": {
var fill = new WasmFill();
fill.setIndex(manager.generate(invocation.getArguments().get(0)));
fill.setValue(new WasmInt32Constant(0));
fill.setCount(manager.generate(invocation.getArguments().get(1)));
return fill;
}
default:
return new WasmUnreachable();
}
}
}

View File

@ -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.DirectMalloc;
import org.teavm.interop.Import; import org.teavm.interop.Import;
import org.teavm.interop.StaticInit; import org.teavm.interop.StaticInit;
import org.teavm.interop.Unmanaged; import org.teavm.interop.Unmanaged;
@ -51,7 +52,7 @@ public final class LaxMalloc {
static { static {
// zero out the control region // zero out the control region
Allocator.fillZero(Address.fromInt(0), ADDR_HEAP_DATA_START); DirectMalloc.zmemset(Address.fromInt(0), ADDR_HEAP_DATA_START);
// initialize heap limit // initialize heap limit
Address.fromInt(ADDR_HEAP_INNER_LIMIT).putInt(ADDR_HEAP_DATA_START); Address.fromInt(ADDR_HEAP_INNER_LIMIT).putInt(ADDR_HEAP_DATA_START);
Address.fromInt(ADDR_HEAP_OUTER_LIMIT).putInt(0x10000); Address.fromInt(ADDR_HEAP_OUTER_LIMIT).putInt(0x10000);
@ -160,7 +161,7 @@ public final class LaxMalloc {
// clear if requested // clear if requested
if(cleared) { if(cleared) {
Allocator.fillZero(ret, sizeBytes); DirectMalloc.zmemset(ret, sizeBytes);
} }
return ret; return ret;
@ -175,7 +176,7 @@ public final class LaxMalloc {
// clear if requested // clear if requested
if(cleared) { if(cleared) {
Allocator.fillZero(ret, sizeBytes); DirectMalloc.zmemset(ret, sizeBytes);
} }
return ret; return ret;
@ -203,7 +204,7 @@ public final class LaxMalloc {
// clear if requested // clear if requested
if(cleared) { if(cleared) {
Allocator.fillZero(ret, sizeBytes); DirectMalloc.zmemset(ret, sizeBytes);
} }
return ret; return ret;
@ -254,7 +255,7 @@ public final class LaxMalloc {
// clear if requested // clear if requested
if(cleared) { if(cleared) {
Allocator.fillZero(ret, sizeBytes); DirectMalloc.zmemset(ret, sizeBytes);
} }
return ret; return ret;

View File

@ -0,0 +1,49 @@
/*
* 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.interop;
/**
* Linear memory allocator for creating "direct buffers" in WASM GC<br><br>
*
* DO NOT USE IN LEGACY WASM BACKEND!!! Make a regular byte array, and use Address.ofData()<br><br>
*
* Similar to dlmalloc and emmalloc (emscripten's malloc)<br><br>
*
* bad things will happen if you free an address that was never allocated
*
* @author lax1dude
*/
public class DirectMalloc {
@UnsupportedOn({Platforms.JAVASCRIPT, Platforms.WEBASSEMBLY, Platforms.C})
public static native Address malloc(int sizeBytes);
@UnsupportedOn({Platforms.JAVASCRIPT, Platforms.WEBASSEMBLY, Platforms.C})
public static native Address calloc(int sizeBytes);
@UnsupportedOn({Platforms.JAVASCRIPT, Platforms.WEBASSEMBLY, Platforms.C})
public static native void free(Address ptr);
@UnsupportedOn({Platforms.JAVASCRIPT, Platforms.WEBASSEMBLY, Platforms.C})
public static native void memcpy(Address dst, Address src, int count);
@UnsupportedOn({Platforms.JAVASCRIPT, Platforms.WEBASSEMBLY, Platforms.C})
public static native void memset(Address ptr, int val, int count);
@UnsupportedOn({Platforms.JAVASCRIPT, Platforms.WEBASSEMBLY, Platforms.C})
public static native void zmemset(Address ptr, int count);
}