Fix generation of integer multiplication in minified mode. Fix String.intern() (see #370)

This commit is contained in:
Alexey Andreev 2018-12-11 17:42:14 +03:00
parent 5db4c11e10
commit d968b20e4c
8 changed files with 32 additions and 23 deletions

View File

@ -34,6 +34,7 @@ import org.teavm.ast.NativeMethodNode;
import org.teavm.ast.NewArrayExpr; import org.teavm.ast.NewArrayExpr;
import org.teavm.ast.NewExpr; import org.teavm.ast.NewExpr;
import org.teavm.ast.NewMultiArrayExpr; import org.teavm.ast.NewMultiArrayExpr;
import org.teavm.ast.OperationType;
import org.teavm.ast.QualificationExpr; import org.teavm.ast.QualificationExpr;
import org.teavm.ast.RecursiveVisitor; import org.teavm.ast.RecursiveVisitor;
import org.teavm.ast.RegularMethodNode; import org.teavm.ast.RegularMethodNode;
@ -200,6 +201,12 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
case COMPARE: case COMPARE:
consumer.consumeFunction("$rt_compare"); consumer.consumeFunction("$rt_compare");
break; break;
case MULTIPLY:
if (expr.getType() == OperationType.INT && !RenderingUtil.isSmallInteger(expr.getFirstOperand())
&& !RenderingUtil.isSmallInteger(expr.getSecondOperand())) {
consumer.consumeFunction("$rt_imul");
}
break;
default: default:
break; break;
} }

View File

@ -247,7 +247,7 @@ public class Renderer implements RenderingManager {
private void renderRuntimeAliases() throws IOException { private void renderRuntimeAliases() throws IOException {
String[] names = { "$rt_throw", "$rt_compare", "$rt_nullCheck", "$rt_cls", "$rt_createArray", String[] names = { "$rt_throw", "$rt_compare", "$rt_nullCheck", "$rt_cls", "$rt_createArray",
"$rt_isInstance", "$rt_nativeThread", "$rt_suspending", "$rt_resuming", "$rt_invalidPointer", "$rt_isInstance", "$rt_nativeThread", "$rt_suspending", "$rt_resuming", "$rt_invalidPointer",
"$rt_s", "$rt_eraseClinit" }; "$rt_s", "$rt_eraseClinit", "$rt_imul" };
boolean first = true; boolean first = true;
for (String name : names) { for (String name : names) {
if (!first) { if (!first) {

View File

@ -19,6 +19,8 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.teavm.ast.ConstantExpr;
import org.teavm.ast.Expr;
public final class RenderingUtil { public final class RenderingUtil {
public static final Set<String> KEYWORDS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("break", "case", public static final Set<String> KEYWORDS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("break", "case",
@ -98,4 +100,18 @@ public final class RenderingUtil {
public static String indexToId(int index) { public static String indexToId(int index) {
return indexToId(index, VARIABLE_START_CHARS); 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);
}
} }

View File

@ -39,8 +39,7 @@ public class RuntimeRenderer {
private static final MethodReference NPE_INIT_METHOD = new MethodReference(NullPointerException.class, private static final MethodReference NPE_INIT_METHOD = new MethodReference(NullPointerException.class,
"<init>", void.class); "<init>", void.class);
private static final MethodDescriptor STRING_INTERN_METHOD = new MethodDescriptor("intern", private static final MethodDescriptor STRING_INTERN_METHOD = new MethodDescriptor("intern", String.class);
String.class, String.class);
private static final MethodDescriptor CURRENT_THREAD_METHOD = new MethodDescriptor("currentThread", private static final MethodDescriptor CURRENT_THREAD_METHOD = new MethodDescriptor("currentThread",
Thread.class); Thread.class);
private static final MethodReference STACK_TRACE_ELEM_INIT = new MethodReference(StackTraceElement.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(); writer.append("function $rt_intern(str) {").indent().softNewLine();
ClassReader stringCls = classSource.get(STRING_CLASS); ClassReader stringCls = classSource.get(STRING_CLASS);
if (stringCls != null && stringCls.getMethod(STRING_INTERN_METHOD) != null) { 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(); .append("(str);").softNewLine();
} else { } else {
writer.append("return str;").softNewLine(); writer.append("return str;").softNewLine();

View File

@ -694,8 +694,8 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
visitBinary(expr, "-", expr.getType() == OperationType.INT); visitBinary(expr, "-", expr.getType() == OperationType.INT);
break; break;
case MULTIPLY: case MULTIPLY:
if (expr.getType() != OperationType.INT || isSmallInteger(expr.getFirstOperand()) if (expr.getType() != OperationType.INT || RenderingUtil.isSmallInteger(expr.getFirstOperand())
|| isSmallInteger(expr.getSecondOperand())) { || RenderingUtil.isSmallInteger(expr.getSecondOperand())) {
visitBinary(expr, "*", expr.getType() == OperationType.INT); visitBinary(expr, "*", expr.getType() == OperationType.INT);
} else { } else {
visitBinaryFunction(expr, naming.getNameForFunction("$rt_imul")); 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 @Override
public void visit(UnaryExpr expr) { public void visit(UnaryExpr expr) {
try { try {

View File

@ -282,7 +282,8 @@ public class StringTest {
@Test @Test
public void interns() { 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 @Test

View File

@ -32,7 +32,7 @@ public class ThreadTest {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Thread.sleep(100); Thread.sleep(100);
long duration = System.currentTimeMillis() - start; long duration = System.currentTimeMillis() - start;
assertTrue("Thread.sleed did not wait enogh", duration >= 100); assertTrue("Thread.sleep did not wait enough", duration >= 100);
} }
@Test @Test

View File

@ -62,7 +62,7 @@ function launchTest(callback) {
if (result instanceof Error) { if (result instanceof Error) {
callback({ callback({
status: "failed", status: "failed",
errorMessage: buildErrorMessage(e) errorMessage: buildErrorMessage(result)
}); });
} else { } else {
callback({ status: "OK" }); callback({ status: "OK" });