From 7d8f5fc9c44b17059c1770ae5305e0eb6aea724d Mon Sep 17 00:00:00 2001 From: lax1dude Date: Fri, 1 Nov 2024 20:19:37 -0700 Subject: [PATCH] DirectMalloc intrinsic --- .../intrinsics/gc/DirectMallocIntrinsic.java | 106 ++++++++++++++++++ .../java/org/teavm/runtime/LaxMalloc.java | 11 +- .../java/org/teavm/interop/DirectMalloc.java | 49 ++++++++ 3 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/DirectMallocIntrinsic.java create mode 100644 interop/core/src/main/java/org/teavm/interop/DirectMalloc.java diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/DirectMallocIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/DirectMallocIntrinsic.java new file mode 100644 index 000000000..121b822fe --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/DirectMallocIntrinsic.java @@ -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(); + } + } + +} diff --git a/core/src/main/java/org/teavm/runtime/LaxMalloc.java b/core/src/main/java/org/teavm/runtime/LaxMalloc.java index f8a391873..5aaec902e 100644 --- a/core/src/main/java/org/teavm/runtime/LaxMalloc.java +++ b/core/src/main/java/org/teavm/runtime/LaxMalloc.java @@ -16,6 +16,7 @@ package org.teavm.runtime; import org.teavm.interop.Address; +import org.teavm.interop.DirectMalloc; import org.teavm.interop.Import; import org.teavm.interop.StaticInit; import org.teavm.interop.Unmanaged; @@ -51,7 +52,7 @@ public final class LaxMalloc { static { // 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 Address.fromInt(ADDR_HEAP_INNER_LIMIT).putInt(ADDR_HEAP_DATA_START); Address.fromInt(ADDR_HEAP_OUTER_LIMIT).putInt(0x10000); @@ -160,7 +161,7 @@ public final class LaxMalloc { // clear if requested if(cleared) { - Allocator.fillZero(ret, sizeBytes); + DirectMalloc.zmemset(ret, sizeBytes); } return ret; @@ -175,7 +176,7 @@ public final class LaxMalloc { // clear if requested if(cleared) { - Allocator.fillZero(ret, sizeBytes); + DirectMalloc.zmemset(ret, sizeBytes); } return ret; @@ -203,7 +204,7 @@ public final class LaxMalloc { // clear if requested if(cleared) { - Allocator.fillZero(ret, sizeBytes); + DirectMalloc.zmemset(ret, sizeBytes); } return ret; @@ -254,7 +255,7 @@ public final class LaxMalloc { // clear if requested if(cleared) { - Allocator.fillZero(ret, sizeBytes); + DirectMalloc.zmemset(ret, sizeBytes); } return ret; diff --git a/interop/core/src/main/java/org/teavm/interop/DirectMalloc.java b/interop/core/src/main/java/org/teavm/interop/DirectMalloc.java new file mode 100644 index 000000000..f26ab0c49 --- /dev/null +++ b/interop/core/src/main/java/org/teavm/interop/DirectMalloc.java @@ -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

+ * + * DO NOT USE IN LEGACY WASM BACKEND!!! Make a regular byte array, and use Address.ofData()

+ * + * Similar to dlmalloc and emmalloc (emscripten's malloc)

+ * + * 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); + +}