diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/AddressIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/AddressIntrinsic.java new file mode 100644 index 000000000..f8aa3dd0f --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/AddressIntrinsic.java @@ -0,0 +1,157 @@ +/* + * Copyright 2024 Alexey Andreev. + * + * 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.stream.Collectors; +import org.teavm.ast.InvocationExpr; +import org.teavm.backend.wasm.WasmRuntime; +import org.teavm.backend.wasm.model.WasmNumType; +import org.teavm.backend.wasm.model.expression.WasmCall; +import org.teavm.backend.wasm.model.expression.WasmConversion; +import org.teavm.backend.wasm.model.expression.WasmExpression; +import org.teavm.backend.wasm.model.expression.WasmInt32Constant; +import org.teavm.backend.wasm.model.expression.WasmInt32Subtype; +import org.teavm.backend.wasm.model.expression.WasmInt64Subtype; +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.WasmLoadFloat32; +import org.teavm.backend.wasm.model.expression.WasmLoadFloat64; +import org.teavm.backend.wasm.model.expression.WasmLoadInt32; +import org.teavm.backend.wasm.model.expression.WasmLoadInt64; +import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; +import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; +import org.teavm.backend.wasm.model.expression.WasmStoreInt32; +import org.teavm.backend.wasm.model.expression.WasmStoreInt64; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; + +public class AddressIntrinsic implements WasmGCIntrinsic { + + @Override + public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext manager) { + switch (invocation.getMethod().getName()) { + case "toInt": + case "toStructure": + return manager.generate(invocation.getArguments().get(0)); + case "toLong": { + WasmExpression value = manager.generate(invocation.getArguments().get(0)); + return new WasmConversion(WasmNumType.INT32, WasmNumType.INT64, false, value); + } + case "fromInt": + return manager.generate(invocation.getArguments().get(0)); + case "fromLong": { + WasmExpression value = manager.generate(invocation.getArguments().get(0)); + return new WasmConversion(WasmNumType.INT64, WasmNumType.INT32, false, value); + } + case "add": { + WasmExpression base = manager.generate(invocation.getArguments().get(0)); + if (invocation.getMethod().parameterCount() == 1) { + WasmExpression offset = manager.generate(invocation.getArguments().get(1)); + if (invocation.getMethod().parameterType(0) == ValueType.LONG) { + offset = new WasmConversion(WasmNumType.INT64, WasmNumType.INT32, false, offset); + } + return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset); + } else { + throw new IllegalArgumentException(invocation.getMethod().toString()); + } + } + case "getByte": + return new WasmLoadInt32(1, manager.generate(invocation.getArguments().get(0)), + WasmInt32Subtype.INT8); + case "getShort": + return new WasmLoadInt32(2, manager.generate(invocation.getArguments().get(0)), + WasmInt32Subtype.INT16); + case "getChar": + return new WasmLoadInt32(2, manager.generate(invocation.getArguments().get(0)), + WasmInt32Subtype.UINT16); + case "getAddress": + case "getInt": + return new WasmLoadInt32(4, manager.generate(invocation.getArguments().get(0)), + WasmInt32Subtype.INT32); + case "getLong": + return new WasmLoadInt64(8, manager.generate(invocation.getArguments().get(0)), + WasmInt64Subtype.INT64); + case "getFloat": + return new WasmLoadFloat32(4, manager.generate(invocation.getArguments().get(0))); + case "getDouble": + return new WasmLoadFloat64(8, manager.generate(invocation.getArguments().get(0))); + case "putByte": { + WasmExpression address = manager.generate(invocation.getArguments().get(0)); + WasmExpression value = manager.generate(invocation.getArguments().get(1)); + return new WasmStoreInt32(1, address, value, WasmInt32Subtype.INT8); + } + case "putShort": { + WasmExpression address = manager.generate(invocation.getArguments().get(0)); + WasmExpression value = manager.generate(invocation.getArguments().get(1)); + return new WasmStoreInt32(2, address, value, WasmInt32Subtype.INT16); + } + case "putChar": { + WasmExpression address = manager.generate(invocation.getArguments().get(0)); + WasmExpression value = manager.generate(invocation.getArguments().get(1)); + return new WasmStoreInt32(2, address, value, WasmInt32Subtype.UINT16); + } + case "putAddress": + case "putInt": { + WasmExpression address = manager.generate(invocation.getArguments().get(0)); + WasmExpression value = manager.generate(invocation.getArguments().get(1)); + return new WasmStoreInt32(4, address, value, WasmInt32Subtype.INT32); + } + case "putLong": { + WasmExpression address = manager.generate(invocation.getArguments().get(0)); + WasmExpression value = manager.generate(invocation.getArguments().get(1)); + return new WasmStoreInt64(8, address, value, WasmInt64Subtype.INT64); + } + case "putFloat": { + WasmExpression address = manager.generate(invocation.getArguments().get(0)); + WasmExpression value = manager.generate(invocation.getArguments().get(1)); + return new WasmStoreFloat32(4, address, value); + } + case "putDouble": { + WasmExpression address = manager.generate(invocation.getArguments().get(0)); + WasmExpression value = manager.generate(invocation.getArguments().get(1)); + return new WasmStoreFloat64(8, address, value); + } + case "sizeOf": + return new WasmInt32Constant(4); + case "align": { + MethodReference delegate = new MethodReference(WasmRuntime.class.getName(), + invocation.getMethod().getDescriptor()); + WasmCall call = new WasmCall(manager.functions().forStaticMethod(delegate)); + call.getArguments().addAll(invocation.getArguments().stream() + .map(arg -> manager.generate(arg)) + .collect(Collectors.toList())); + return call; + } + case "isLessThan": + return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_UNSIGNED, + manager.generate(invocation.getArguments().get(0)), + manager.generate(invocation.getArguments().get(1))); + case "diff": { + WasmExpression result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SUB, + manager.generate(invocation.getArguments().get(0)), + manager.generate(invocation.getArguments().get(1)) + ); + result = new WasmConversion(WasmNumType.INT32, WasmNumType.INT64, true, result); + result.setLocation(invocation.getLocation()); + return result; + } + default: + throw new IllegalArgumentException(invocation.getMethod().toString()); + } + } + +} 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 index 121b822fe..6383308af 100644 --- 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 @@ -16,8 +16,6 @@ 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; @@ -25,11 +23,10 @@ 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 { +public class DirectMallocIntrinsic implements WasmGCIntrinsic { 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, @@ -38,41 +35,22 @@ public class DirectMallocIntrinsic implements WasmIntrinsic { 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) { + public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext manager) { switch (invocation.getMethod().getName()) { case "malloc": { - var function = manager.getFunctions().forStaticMethod(LAX_MALLOC); + var function = manager.functions().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 function = manager.functions().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 function = manager.functions().forStaticMethod(LAX_FREE); var call = new WasmCall(function); call.getArguments().add(manager.generate(invocation.getArguments().get(0))); return call; diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java index 00919cf13..b100d0552 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java @@ -25,6 +25,8 @@ import org.teavm.backend.wasm.model.expression.WasmIntType; import org.teavm.backend.wasm.runtime.StringInternPool; import org.teavm.backend.wasm.runtime.gc.WasmGCResources; import org.teavm.common.ServiceRepository; +import org.teavm.interop.Address; +import org.teavm.interop.DirectMalloc; import org.teavm.model.ClassReaderSource; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; @@ -51,6 +53,8 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider { fillArray(); fillString(); fillResources(); + fillDirectMalloc(); + fillAddress(); for (var entry : customIntrinsics.entrySet()) { add(entry.getKey(), entry.getValue()); } @@ -166,6 +170,48 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider { add(new MethodReference(WasmGCResources.class, "readSingleByte", int.class, int.class), intrinsic); } + private void fillDirectMalloc() { + var intrinsic = new DirectMallocIntrinsic(); + add(new MethodReference(DirectMalloc.class, "malloc", int.class, Address.class), intrinsic); + add(new MethodReference(DirectMalloc.class, "calloc", int.class, Address.class), intrinsic); + add(new MethodReference(DirectMalloc.class, "free", Address.class, void.class), intrinsic); + add(new MethodReference(DirectMalloc.class, "memcpy", Address.class, Address.class, int.class, void.class), intrinsic); + add(new MethodReference(DirectMalloc.class, "memset", Address.class, int.class, int.class, void.class), intrinsic); + add(new MethodReference(DirectMalloc.class, "zmemset", Address.class, int.class, void.class), intrinsic); + } + + private void fillAddress() { + var intrinsic = new AddressIntrinsic(); + add(new MethodReference(Address.class, "add", int.class, Address.class), intrinsic); + add(new MethodReference(Address.class, "add", long.class, Address.class), intrinsic); + add(new MethodReference(Address.class, "isLessThan", Address.class, boolean.class), intrinsic); + add(new MethodReference(Address.class, "toInt", int.class), intrinsic); + add(new MethodReference(Address.class, "toLong", long.class), intrinsic); + //add(new MethodReference(Address.class, "toStructure", ?????), intrinsic); //TODO + add(new MethodReference(Address.class, "getByte", byte.class), intrinsic); + add(new MethodReference(Address.class, "putByte", byte.class, void.class), intrinsic); + add(new MethodReference(Address.class, "getChar", char.class), intrinsic); + add(new MethodReference(Address.class, "putChar", char.class, void.class), intrinsic); + add(new MethodReference(Address.class, "getShort", short.class), intrinsic); + add(new MethodReference(Address.class, "putShort", short.class, void.class), intrinsic); + add(new MethodReference(Address.class, "getInt", int.class), intrinsic); + add(new MethodReference(Address.class, "putInt", int.class, void.class), intrinsic); + add(new MethodReference(Address.class, "getLong", long.class), intrinsic); + add(new MethodReference(Address.class, "putLong", long.class, void.class), intrinsic); + add(new MethodReference(Address.class, "getFloat", float.class), intrinsic); + add(new MethodReference(Address.class, "putFloat", float.class, void.class), intrinsic); + add(new MethodReference(Address.class, "getDouble", double.class), intrinsic); + add(new MethodReference(Address.class, "putDouble", double.class, void.class), intrinsic); + add(new MethodReference(Address.class, "getAddress", Address.class), intrinsic); + add(new MethodReference(Address.class, "putAddress", Address.class, void.class), intrinsic); + add(new MethodReference(Address.class, "fromInt", int.class, Address.class), intrinsic); + add(new MethodReference(Address.class, "fromLong", long.class, Address.class), intrinsic); + add(new MethodReference(Address.class, "align", Address.class, int.class, Address.class), intrinsic); + add(new MethodReference(Address.class, "sizeOf", int.class), intrinsic); + add(new MethodReference(Address.class, "add", Class.class, int.class), intrinsic); + add(new MethodReference(Address.class, "diff", Address.class, long.class), intrinsic); + } + private void add(MethodReference methodRef, WasmGCIntrinsic intrinsic) { intrinsics.put(methodRef, new IntrinsicContainer(intrinsic)); }