From 530b6a5da5f0a2b16e5bef8c2b5022642392870e Mon Sep 17 00:00:00 2001 From: lax1dude Date: Mon, 2 Dec 2024 19:47:22 -0800 Subject: [PATCH 1/2] Add class transformers to convert functions to native --- .../org/teavm/backend/wasm/WasmTarget.java | 2 + .../BaseClassesTransformation.java | 41 +++++++++++++++++++ .../gc/BaseClassesTransformation.java | 11 +++++ 3 files changed, 54 insertions(+) create mode 100644 core/src/main/java/org/teavm/backend/wasm/transformation/BaseClassesTransformation.java diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index 728287f18..c94060dbd 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -115,6 +115,7 @@ import org.teavm.backend.wasm.render.WasmBinaryWriter; import org.teavm.backend.wasm.render.WasmCRenderer; import org.teavm.backend.wasm.render.WasmRenderer; import org.teavm.backend.wasm.runtime.WasmSupport; +import org.teavm.backend.wasm.transformation.BaseClassesTransformation; import org.teavm.backend.wasm.transformation.IndirectCallTraceTransformation; import org.teavm.backend.wasm.transformation.MemoryAccessTraceTransformation; import org.teavm.backend.wasm.transformation.WasiFileSystemProviderTransformer; @@ -241,6 +242,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { public List getTransformers() { List transformers = new ArrayList<>(); transformers.add(new ClassPatch()); + transformers.add(new BaseClassesTransformation()); transformers.add(new WasmDependencyListener()); if (runtimeType == WasmRuntimeType.WASI) { transformers.add(new WasiSupportClassTransformer()); diff --git a/core/src/main/java/org/teavm/backend/wasm/transformation/BaseClassesTransformation.java b/core/src/main/java/org/teavm/backend/wasm/transformation/BaseClassesTransformation.java new file mode 100644 index 000000000..abcfb4ae4 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/transformation/BaseClassesTransformation.java @@ -0,0 +1,41 @@ +/* + * 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.transformation; + +import org.teavm.model.ClassHolder; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.model.ClassHolderTransformerContext; +import org.teavm.model.ElementModifier; + +public class BaseClassesTransformation implements ClassHolderTransformer { + + @Override + public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) { + if (cls.getName().equals("java.lang.Integer") || cls.getName().equals("java.lang.Long")) { + for (var method : cls.getMethods()) { + switch (method.getName()) { + case "numberOfLeadingZeros": + case "numberOfTrailingZeros": + case "bitCount": + method.setProgram(null); + method.getModifiers().add(ElementModifier.NATIVE); + break; + } + } + } + } + +} diff --git a/core/src/main/java/org/teavm/backend/wasm/transformation/gc/BaseClassesTransformation.java b/core/src/main/java/org/teavm/backend/wasm/transformation/gc/BaseClassesTransformation.java index 6b24229c5..ce0ea18ef 100644 --- a/core/src/main/java/org/teavm/backend/wasm/transformation/gc/BaseClassesTransformation.java +++ b/core/src/main/java/org/teavm/backend/wasm/transformation/gc/BaseClassesTransformation.java @@ -121,6 +121,17 @@ public class BaseClassesTransformation implements ClassHolderTransformer { var clear = cls.getMethod(new MethodDescriptor("clear", void.class)); clear.getModifiers().add(ElementModifier.NATIVE); clear.setProgram(null); + } else if (cls.getName().equals("java.lang.Integer") || cls.getName().equals("java.lang.Long")) { + for (var method : cls.getMethods()) { + switch (method.getName()) { + case "numberOfLeadingZeros": + case "numberOfTrailingZeros": + case "bitCount": + method.setProgram(null); + method.getModifiers().add(ElementModifier.NATIVE); + break; + } + } } } From 42fcbb71a7483666a5426ea5abea9736ec50e323 Mon Sep 17 00:00:00 2001 From: lax1dude Date: Mon, 2 Dec 2024 19:49:20 -0800 Subject: [PATCH 2/2] Add missing java.lang.Long unit tests --- .../teavm/classlib/java/lang/LongTest.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java index 0920b99f3..183f05698 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java @@ -86,6 +86,35 @@ public class LongTest { assertEquals(0xF63BA00000000000L, Long.reverse(0x5DC6F)); } + @Test + public void numberOfLeadingZerosComputed() { + assertEquals(0, Long.numberOfLeadingZeros(-1L)); + assertEquals(1, Long.numberOfLeadingZeros(0x4000000000000000L)); + assertEquals(1, Long.numberOfLeadingZeros(0x4000000000000123L)); + assertEquals(1, Long.numberOfLeadingZeros(0x7FFFFFFFFFFFFFFFL)); + assertEquals(63, Long.numberOfLeadingZeros(1L)); + assertEquals(62, Long.numberOfLeadingZeros(2L)); + assertEquals(62, Long.numberOfLeadingZeros(3L)); + assertEquals(0, Long.numberOfLeadingZeros(0x8000000000000000L)); + assertEquals(0, Long.numberOfLeadingZeros(0x8000000000000123L)); + assertEquals(0, Long.numberOfLeadingZeros(0xFFFFFFFFFFFFFFFFL)); + assertEquals(64, Long.numberOfLeadingZeros(0L)); + } + + @Test + public void numberOfTrailingZerosComputed() { + assertEquals(1, Long.numberOfTrailingZeros(0xFFFFFFFFFFFFFFFEL)); + assertEquals(1, Long.numberOfTrailingZeros(0x4000000000000002L)); + assertEquals(1, Long.numberOfTrailingZeros(0x0000000000000002L)); + assertEquals(63, Long.numberOfTrailingZeros(0x8000000000000000L)); + assertEquals(62, Long.numberOfTrailingZeros(0x4000000000000000L)); + assertEquals(62, Long.numberOfTrailingZeros(0xC000000000000000L)); + assertEquals(0, Long.numberOfTrailingZeros(0x0000000000000001L)); + assertEquals(0, Long.numberOfTrailingZeros(0x1230000000000003L)); + assertEquals(0, Long.numberOfTrailingZeros(0xFFFFFFFFFFFFFFFFL)); + assertEquals(64, Long.numberOfTrailingZeros(0L)); + } + @Test public void highestOneBit() { assertEquals(1L << 63, Long.highestOneBit(-1L));