From 5c613d2f7fde15fce1ac9d8208a7052c7b65db19 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Thu, 27 Feb 2014 16:06:22 +0400 Subject: [PATCH] Implements Double.parseDouble. Fixes bugs. Disabled devirtualization optimization due to bugs --- .../org/teavm/classlib/java/lang/TDouble.java | 130 +++++++++++++++++- .../org/teavm/classlib/java/lang/TMath.java | 20 +++ .../org/teavm/classlib/java/util/TArrays.java | 3 + .../java/util/concurrent/TExecutor.java | 26 ++++ .../teavm/classlib/java/lang/DoubleTest.java | 51 +++++++ .../teavm/javascript/JavascriptBuilder.java | 6 +- .../java/org/teavm/javascript/Renderer.java | 8 +- .../java/org/teavm/parsing/ProgramParser.java | 9 ++ .../resources/org/teavm/javascript/runtime.js | 8 +- 9 files changed, 251 insertions(+), 10 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/concurrent/TExecutor.java create mode 100644 teavm-classlib/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java index 8c95c4a2e..a99722a4d 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java @@ -22,7 +22,9 @@ import org.teavm.javascript.ni.Rename; * * @author Alexey Andreev */ -public class TDouble extends TNumber { +public class TDouble extends TNumber implements TComparable { + public static double POSITIVE_INFINITY = 1 / 0.0; + public static double NEGATIVE_INFINITY = -POSITIVE_INFINITY; private double value; public TDouble(double value) { @@ -57,6 +59,123 @@ public class TDouble extends TNumber { return TString.wrap(new TStringBuilder().append(d).toString()); } + public static TDouble valueOf(TString string) { + return valueOf(parseDouble(string)); + } + + public static double parseDouble(TString string) throws TNumberFormatException { + // TODO: parse infinite and different radix + string = string.trim(); + boolean negative = false; + int index = 0; + if (string.charAt(index) == '-') { + ++index; + negative = true; + } else if (string.charAt(index) == '+') { + ++index; + } + char c = string.charAt(index); + if (c < '0' || c > '9') { + throw new TNumberFormatException(); + } + long mantissa = 0; + int exp = 0; + while (string.charAt(index) == '0') { + if (++index == string.length()) { + return 0; + } + } + while (index < string.length()) { + c = string.charAt(index); + if (c < '0' || c > '9') { + break; + } + if (mantissa < 1E17) { + mantissa = mantissa * 10 + (c - '0'); + } else { + ++exp; + } + ++index; + } + if (index < string.length() && string.charAt(index) == '.') { + ++index; + boolean hasOneDigit = false; + while (index < string.length()) { + c = string.charAt(index); + if (c < '0' || c > '9') { + break; + } + if (mantissa < 1E17) { + mantissa = mantissa * 10 + (c - '0'); + --exp; + } + ++index; + hasOneDigit = true; + } + if (!hasOneDigit) { + throw new TNumberFormatException(); + } + } + if (index < string.length()) { + c = string.charAt(index); + if (c != 'e' && c != 'E') { + throw new TNumberFormatException(); + } + ++index; + boolean negativeExp = false; + if (string.charAt(index) == '-') { + ++index; + negativeExp = true; + } else if (string.charAt(index) == '+') { + ++index; + } + int numExp = 0; + boolean hasOneDigit = false; + while (index < string.length()) { + c = string.charAt(index); + if (c < '0' || c > '9') { + break; + } + numExp = 10 * numExp + (c - '0'); + hasOneDigit = true; + ++index; + } + if (!hasOneDigit) { + throw new TNumberFormatException(); + } + if (negativeExp) { + numExp = -numExp; + } + exp += numExp; + } + if (exp > 308 || exp == 308 && mantissa > 17976931348623157L) { + return !negative ? POSITIVE_INFINITY : NEGATIVE_INFINITY; + } + if (negative) { + mantissa = -mantissa; + } + return mantissa * decimalExponent(exp); + } + + private static double decimalExponent(int n) { + double d; + if (n < 0) { + d = 0.1; + n = -n; + } else { + d = 10; + } + double result = 1; + while (n != 0) { + if (n % 2 != 0) { + result *= d; + } + d *= d; + n /= 2; + } + return result; + } + @Override @Rename("toString") public TString toString0() { @@ -71,6 +190,15 @@ public class TDouble extends TNumber { return other instanceof TDouble && ((TDouble)other).value == value; } + public static int compare(double a, double b) { + return a > b ? 1 : a < b ? -1 : 0; + } + + @Override + public int compareTo(TDouble other) { + return compare(value, other.value); + } + @GeneratedBy(DoubleNativeGenerator.class) public static native boolean isNaN(double v); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java index 4b34b6b36..5eedf399a 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TMath.java @@ -38,4 +38,24 @@ public final class TMath extends TObject { public static long max(long a, long b) { return a > b ? a : b; } + + public static double min(double a, double b) { + return a < b ? a : b; + } + + public static double max(double a, double b) { + return a > b ? a : b; + } + + public static int abs(int n) { + return n > 0 ? n : -n; + } + + public static long abs(long n) { + return n > 0 ? n : -n; + } + + public static double abs(double n) { + return n > 0 ? n : -n; + } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java index e968d6779..c0b0ced22 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java @@ -219,6 +219,9 @@ public class TArrays extends TObject { @SuppressWarnings("unchecked") public static void sort(T[] a, TComparator c) { + if (a.length == 0) { + return; + } Object[] first = a; Object[] second = new Object[a.length]; int chunkSize = 1; diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/concurrent/TExecutor.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/concurrent/TExecutor.java new file mode 100644 index 000000000..d0fa1c61c --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/concurrent/TExecutor.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 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.classlib.java.util.concurrent; + +import org.teavm.classlib.java.lang.TRunnable; + +/** + * + * @author Alexey Andreev + */ +public interface TExecutor { + void execute(TRunnable command); +} diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java new file mode 100644 index 000000000..1254366af --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 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.classlib.java.lang; + +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class DoubleTest { + @Test + public void parsed() { + assertEquals(23, Double.parseDouble("23"), 1E-12); + assertEquals(23, Double.parseDouble("23.0"), 1E-12); + assertEquals(23, Double.parseDouble("23E0"), 1E-12); + assertEquals(23, Double.parseDouble("2.30000E1"), 1E-12); + assertEquals(23, Double.parseDouble("0.23E2"), 1E-12); + assertEquals(23, Double.parseDouble("0.000023E6"), 1E-12); + assertEquals(23, Double.parseDouble("00230000e-4"), 1E-12); + assertEquals(23, Double.parseDouble("2300000000000000000000e-20"), 1E-12); + assertEquals(23, Double.parseDouble("2300000000000000000000e-20"), 1E-12); + } + + @Test + public void negativeParsed() { + assertEquals(-23, Double.parseDouble("-23"), 1E-12); + } + + @Test + public void zeroParsed() { + assertEquals(0, Double.parseDouble("0.0"), 1E-12); + assertEquals(0, Double.parseDouble("23E-8000"), 1E-12); + assertEquals(0, Double.parseDouble("00000"), 1E-12); + assertEquals(0, Double.parseDouble("00000.0000"), 1E-12); + } +} diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java index 256597f30..f66b9db8b 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java @@ -158,8 +158,8 @@ public class JavascriptBuilder implements JavascriptBuilderHost { Linker linker = new Linker(dependencyChecker); ListableClassHolderSource classSet = linker.link(classSource); Decompiler decompiler = new Decompiler(classSet, classLoader, executor); - devirtualize(classSet, dependencyChecker); - executor.complete(); + /*devirtualize(classSet, dependencyChecker); + executor.complete();*/ ClassSetOptimizer optimizer = new ClassSetOptimizer(executor); optimizer.optimizeAll(classSet); executor.complete(); @@ -198,6 +198,8 @@ public class JavascriptBuilder implements JavascriptBuilderHost { } } + // TODO: repair devirtualization + @SuppressWarnings("unused") private void devirtualize(ListableClassHolderSource classes, DependencyInfo dependency) { final Devirtualization devirtualization = new Devirtualization(dependency, classes); for (String className : classes.getClassNames()) { diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index aa897235a..6d5f73bb5 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -1274,11 +1274,9 @@ public class Renderer implements ExprVisitor, StatementVisitor { .appendClass(catchClause.getExceptionType()); } writer.append(")").ws().append("{").indent().softNewLine(); - if (statement.getExceptionVariable() != catchClause.getExceptionVariable()) { - if (catchClause.getExceptionVariable() != null) { - writer.append(variableName(catchClause.getExceptionVariable())).ws().append("=").ws() - .append("$e;").softNewLine(); - } + if (catchClause.getExceptionVariable() != null) { + writer.append(variableName(catchClause.getExceptionVariable())).ws().append("=").ws() + .append("$je;").softNewLine(); } for (Statement part : catchClause.getHandler()) { part.acceptVisitor(this); diff --git a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java index 111e97529..3b3469423 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -89,6 +89,15 @@ public class ProgramParser { program.basicBlockAt(0).getInstructions().add(insn); doAnalyze(method); assemble(); + for (int i = 0; i < program.basicBlockCount(); ++i) { + BasicBlock block = program.basicBlockAt(i); + for (int j = 0; j < block.getTryCatchBlocks().size(); ++j) { + TryCatchBlock tryCatch = block.getTryCatchBlocks().get(j); + if (tryCatch.getHandler() == block) { + block.getTryCatchBlocks().remove(j--); + } + } + } return program; } diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index 3a1a07e5d..592b946b5 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -228,8 +228,12 @@ $rt_init = function(cls, constructor, args) { return obj; } $rt_throw = function(ex) { - var err = new Error("Java exception thrown"); - err.$javaException = ex; + var err = ex.$jsException; + if (!err) { + var err = new Error("Java exception thrown"); + err.$javaException = ex; + ex.$jsException = err; + } throw err; } $rt_byteToInt = function(value) {