diff --git a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index 9aa8695dc..38b6a87dd 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -53,5 +53,7 @@ public class JCLPlugin implements TeaVMPlugin { String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class, CallSite.class), new LambdaMetafactorySubstitutor()); host.add(new ScalaHacks()); + + host.add(new NumericClassTransformer()); } } diff --git a/classlib/src/main/java/org/teavm/classlib/impl/NumericClassTransformer.java b/classlib/src/main/java/org/teavm/classlib/impl/NumericClassTransformer.java new file mode 100644 index 000000000..4b23fbcf1 --- /dev/null +++ b/classlib/src/main/java/org/teavm/classlib/impl/NumericClassTransformer.java @@ -0,0 +1,93 @@ +/* + * Copyright 2017 konsoletyper. + * + * 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.classlib.impl; + +import org.teavm.diagnostics.Diagnostics; +import org.teavm.model.BasicBlock; +import org.teavm.model.ClassHolder; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.ElementModifier; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodHolder; +import org.teavm.model.Program; +import org.teavm.model.ValueType; +import org.teavm.model.Variable; +import org.teavm.model.instructions.BinaryInstruction; +import org.teavm.model.instructions.BinaryOperation; +import org.teavm.model.instructions.ExitInstruction; +import org.teavm.model.instructions.NumericOperandType; + +public class NumericClassTransformer implements ClassHolderTransformer { + @Override + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { + switch (cls.getName()) { + case "java.lang.Integer": + transformInteger(cls); + break; + case "java.lang.Long": + transformLong(cls); + break; + case "java.lang.Float": + transformFloat(cls); + break; + case "java.lang.Double": + transformDouble(cls); + break; + } + } + + private void transformInteger(ClassHolder cls) { + transformCompareMethod(cls, ValueType.INTEGER, NumericOperandType.INT); + } + + private void transformLong(ClassHolder cls) { + transformCompareMethod(cls, ValueType.LONG, NumericOperandType.LONG); + } + + private void transformFloat(ClassHolder cls) { + transformCompareMethod(cls, ValueType.FLOAT, NumericOperandType.FLOAT); + } + + private void transformDouble(ClassHolder cls) { + transformCompareMethod(cls, ValueType.DOUBLE, NumericOperandType.DOUBLE); + } + + private void transformCompareMethod(ClassHolder cls, ValueType type, NumericOperandType insnType) { + MethodHolder method = cls.getMethod(new MethodDescriptor("compare", type, type, ValueType.INTEGER)); + Program program = new Program(); + + program.createVariable(); + Variable firstArg = program.createVariable(); + Variable secondArg = program.createVariable(); + Variable result = program.createVariable(); + + BasicBlock block = program.createBasicBlock(); + + BinaryInstruction insn = new BinaryInstruction(BinaryOperation.COMPARE, insnType); + insn.setFirstOperand(firstArg); + insn.setSecondOperand(secondArg); + insn.setReceiver(result); + block.add(insn); + + ExitInstruction exit = new ExitInstruction(); + exit.setValueToReturn(result); + block.add(exit); + + method.setProgram(program); + method.getModifiers().remove(ElementModifier.NATIVE); + } +} diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/LongNativeGenerator.java b/classlib/src/main/java/org/teavm/classlib/java/lang/LongNativeGenerator.java index 95b76e5e4..851654e29 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/LongNativeGenerator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/LongNativeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 Alexey Andreev. + * Copyright 2017 Alexey Andreev. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,10 +21,6 @@ import org.teavm.backend.javascript.spi.Generator; import org.teavm.backend.javascript.spi.GeneratorContext; import org.teavm.model.MethodReference; -/** - * - * @author Alexey Andreev - */ public class LongNativeGenerator implements Generator { @Override public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { @@ -33,10 +29,6 @@ public class LongNativeGenerator implements Generator { writer.append("return Long_compare(").append(context.getParameterName(1)).append(", ") .append(context.getParameterName(2)).append(");").softNewLine(); break; - case "hashCode": - writer.append("return ").append(context.getParameterName(1)).append(".hi ^ ") - .append(context.getParameterName(1)).append(".lo;").softNewLine(); - break; } } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java index b60345bd9..e2cbe4d1c 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java @@ -203,9 +203,7 @@ public class TDouble extends TNumber implements TComparable { return (int) (h >>> 32) ^ (int) h; } - public static int compare(double a, double b) { - return a > b ? 1 : a < b ? -1 : 0; - } + public static native int compare(double a, double b); @Override public int compareTo(TDouble other) { diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java index 219407578..adf873b64 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java @@ -230,9 +230,7 @@ public class TFloat extends TNumber implements TComparable { return isInfinite(value); } - public static int compare(float f1, float f2) { - return f1 > f2 ? 1 : f2 < f1 ? -1 : 0; - } + public static native int compare(float f1, float f2); @Override public int compareTo(TFloat other) { diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java index 253860aa6..c0457291b 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java @@ -244,9 +244,7 @@ public class TInteger extends TNumber implements TComparable { return compare(value, other.value); } - public static int compare(int x, int y) { - return x > y ? 1 : x < y ? -1 : 0; - } + public static native int compare(int x, int y); public static int numberOfLeadingZeros(int i) { if (i == 0) { diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java index 425fd73c2..a48dc605c 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java @@ -15,8 +15,6 @@ */ package org.teavm.classlib.java.lang; -import org.teavm.backend.javascript.spi.GeneratedBy; - public class TLong extends TNumber implements TComparable { public static final long MIN_VALUE = -0x8000000000000000L; public static final long MAX_VALUE = 0x7FFFFFFFFFFFFFFFL; @@ -199,8 +197,9 @@ public class TLong extends TNumber implements TComparable { return hashCode(value); } - @GeneratedBy(LongNativeGenerator.class) - private static native int hashCode(long value); + private static int hashCode(long value) { + return (int) (value ^ (value >>> 32)); + } @Override public boolean equals(Object other) { @@ -210,7 +209,6 @@ public class TLong extends TNumber implements TComparable { return other instanceof TLong && ((TLong) other).value == value; } - @GeneratedBy(LongNativeGenerator.class) public static native int compare(long a, long b); @Override diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java index 89f4e1d6a..2c698942d 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java @@ -86,4 +86,11 @@ public class DoubleTest { assertEquals("0x0.8p-1022", Double.toHexString(0x0.8p-1022)); assertEquals("0x0.001p-1022", Double.toHexString(0x0.001p-1022)); } + + @Test + public void compares() { + assertTrue(Double.compare(10, 5) > 0); + assertTrue(Double.compare(5, 10) < 0); + assertTrue(Double.compare(5, 5) == 0); + } } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/FloatTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/FloatTest.java index 1f5c8da49..55ef64db9 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/FloatTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/FloatTest.java @@ -85,4 +85,11 @@ public class FloatTest { assertEquals("0x1.0p-126", Float.toHexString((float)Math.pow(2, -126))); assertEquals("0x0.001p-126", Float.toHexString(0x0.001p-126f)); } + + @Test + public void compares() { + assertTrue(Float.compare(10, 5) > 0); + assertTrue(Float.compare(5, 10) < 0); + assertTrue(Float.compare(5, 5) == 0); + } } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java index 5b6db1051..69675fa70 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java @@ -127,4 +127,13 @@ public class IntegerTest { assertEquals(0xFFFFFFFF, Integer.reverse(0xFFFFFFFF)); assertEquals(0xF63BA000, Integer.reverse(0x5DC6F)); } + + @Test + public void compares() { + assertTrue(Integer.compare(10, 5) > 0); + assertTrue(Integer.compare(5, 10) < 0); + assertTrue(Integer.compare(5, 5) == 0); + assertTrue(Integer.compare(Integer.MAX_VALUE, Integer.MIN_VALUE) > 0); + assertTrue(Integer.compare(Integer.MIN_VALUE, Integer.MAX_VALUE) < 0); + } } 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 new file mode 100644 index 000000000..1eee9d544 --- /dev/null +++ b/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017 konsoletyper. + * + * 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.classlib.java.lang; + +import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.teavm.junit.TeaVMTestRunner; + +@RunWith(TeaVMTestRunner.class) +public class LongTest { + @Test + public void compares() { + assertTrue(Long.compare(10, 5) > 0); + assertTrue(Long.compare(5, 10) < 0); + assertTrue(Long.compare(5, 5) == 0); + assertTrue(Long.compare(Long.MAX_VALUE, Long.MIN_VALUE) > 0); + assertTrue(Long.compare(Long.MIN_VALUE, Long.MAX_VALUE) < 0); + } +}