From d968b20e4c855df85e8d61ee71c29bdef149849a Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 11 Dec 2018 17:42:14 +0300 Subject: [PATCH] Fix generation of integer multiplication in minified mode. Fix String.intern() (see #370) --- .../rendering/NameFrequencyEstimator.java | 7 +++++++ .../backend/javascript/rendering/Renderer.java | 2 +- .../javascript/rendering/RenderingUtil.java | 16 ++++++++++++++++ .../javascript/rendering/RuntimeRenderer.java | 5 ++--- .../rendering/StatementRenderer.java | 18 ++---------------- .../teavm/classlib/java/lang/StringTest.java | 3 ++- .../teavm/classlib/java/lang/ThreadTest.java | 2 +- tests/src/test/js/frame.js | 2 +- 8 files changed, 32 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java b/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java index 36cf0f885..eaada83e3 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java @@ -34,6 +34,7 @@ import org.teavm.ast.NativeMethodNode; import org.teavm.ast.NewArrayExpr; import org.teavm.ast.NewExpr; import org.teavm.ast.NewMultiArrayExpr; +import org.teavm.ast.OperationType; import org.teavm.ast.QualificationExpr; import org.teavm.ast.RecursiveVisitor; import org.teavm.ast.RegularMethodNode; @@ -200,6 +201,12 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit case COMPARE: consumer.consumeFunction("$rt_compare"); break; + case MULTIPLY: + if (expr.getType() == OperationType.INT && !RenderingUtil.isSmallInteger(expr.getFirstOperand()) + && !RenderingUtil.isSmallInteger(expr.getSecondOperand())) { + consumer.consumeFunction("$rt_imul"); + } + break; default: break; } diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index 8412e402a..cd72cf654 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -247,7 +247,7 @@ public class Renderer implements RenderingManager { private void renderRuntimeAliases() throws IOException { String[] names = { "$rt_throw", "$rt_compare", "$rt_nullCheck", "$rt_cls", "$rt_createArray", "$rt_isInstance", "$rt_nativeThread", "$rt_suspending", "$rt_resuming", "$rt_invalidPointer", - "$rt_s", "$rt_eraseClinit" }; + "$rt_s", "$rt_eraseClinit", "$rt_imul" }; boolean first = true; for (String name : names) { if (!first) { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingUtil.java b/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingUtil.java index 580f456e8..c9bdc2a16 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingUtil.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingUtil.java @@ -19,6 +19,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import org.teavm.ast.ConstantExpr; +import org.teavm.ast.Expr; public final class RenderingUtil { public static final Set KEYWORDS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("break", "case", @@ -98,4 +100,18 @@ public final class RenderingUtil { public static String indexToId(int index) { return indexToId(index, VARIABLE_START_CHARS); } + + public static boolean isSmallInteger(Expr expr) { + if (!(expr instanceof ConstantExpr)) { + return false; + } + + Object constant = ((ConstantExpr) expr).getValue(); + if (!(constant instanceof Integer)) { + return false; + } + + int value = (Integer) constant; + return Math.abs(value) < (1 << 18); + } } diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java index c60be1bc3..f28254b3b 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/RuntimeRenderer.java @@ -39,8 +39,7 @@ public class RuntimeRenderer { private static final MethodReference NPE_INIT_METHOD = new MethodReference(NullPointerException.class, "", void.class); - private static final MethodDescriptor STRING_INTERN_METHOD = new MethodDescriptor("intern", - String.class, String.class); + private static final MethodDescriptor STRING_INTERN_METHOD = new MethodDescriptor("intern", String.class); private static final MethodDescriptor CURRENT_THREAD_METHOD = new MethodDescriptor("currentThread", Thread.class); private static final MethodReference STACK_TRACE_ELEM_INIT = new MethodReference(StackTraceElement.class, @@ -154,7 +153,7 @@ public class RuntimeRenderer { writer.append("function $rt_intern(str) {").indent().softNewLine(); ClassReader stringCls = classSource.get(STRING_CLASS); if (stringCls != null && stringCls.getMethod(STRING_INTERN_METHOD) != null) { - writer.append("return ").appendMethodBody(new MethodReference(String.class, "intern", String.class)) + writer.append("return ").appendMethodBody(new MethodReference(STRING_CLASS, STRING_INTERN_METHOD)) .append("(str);").softNewLine(); } else { writer.append("return str;").softNewLine(); diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java index 0bc748d6d..35272019e 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java @@ -694,8 +694,8 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { visitBinary(expr, "-", expr.getType() == OperationType.INT); break; case MULTIPLY: - if (expr.getType() != OperationType.INT || isSmallInteger(expr.getFirstOperand()) - || isSmallInteger(expr.getSecondOperand())) { + if (expr.getType() != OperationType.INT || RenderingUtil.isSmallInteger(expr.getFirstOperand()) + || RenderingUtil.isSmallInteger(expr.getSecondOperand())) { visitBinary(expr, "*", expr.getType() == OperationType.INT); } else { visitBinaryFunction(expr, naming.getNameForFunction("$rt_imul")); @@ -764,20 +764,6 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { } } - private static boolean isSmallInteger(Expr expr) { - if (!(expr instanceof ConstantExpr)) { - return false; - } - - Object constant = ((ConstantExpr) expr).getValue(); - if (!(constant instanceof Integer)) { - return false; - } - - int value = (Integer) constant; - return Math.abs(value) < (1 << 18); - } - @Override public void visit(UnaryExpr expr) { try { diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/StringTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/StringTest.java index 152cff481..fb0eefff7 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/StringTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/StringTest.java @@ -282,7 +282,8 @@ public class StringTest { @Test public void interns() { - assertSame(("ab" + "c").intern(), ("a" + "bc").intern()); + assertSame("xabc".substring(1).intern(), "abcx".substring(0, 3).intern()); + assertSame("xabc".substring(1).intern(), "abc"); } @Test diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/ThreadTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/ThreadTest.java index ae7b4ff41..6072bbcdf 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/ThreadTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/ThreadTest.java @@ -32,7 +32,7 @@ public class ThreadTest { long start = System.currentTimeMillis(); Thread.sleep(100); long duration = System.currentTimeMillis() - start; - assertTrue("Thread.sleed did not wait enogh", duration >= 100); + assertTrue("Thread.sleep did not wait enough", duration >= 100); } @Test diff --git a/tests/src/test/js/frame.js b/tests/src/test/js/frame.js index cbbe3fac3..d81aaedb3 100644 --- a/tests/src/test/js/frame.js +++ b/tests/src/test/js/frame.js @@ -62,7 +62,7 @@ function launchTest(callback) { if (result instanceof Error) { callback({ status: "failed", - errorMessage: buildErrorMessage(e) + errorMessage: buildErrorMessage(result) }); } else { callback({ status: "OK" });