JS: generate shorter names for Long operations and array creation in minified mode

This commit is contained in:
Alexey Andreev 2020-03-04 13:23:19 +03:00
parent 3ff05d1c5d
commit 37f07b80c3
6 changed files with 173 additions and 30 deletions

View File

@ -417,6 +417,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
if (renderer.isLongLibraryUsed()) {
runtimeRenderer.renderHandWrittenRuntime("long.js");
renderer.renderLongRuntimeAliases();
}
if (renderer.isThreadLibraryUsed()) {
runtimeRenderer.renderHandWrittenRuntime("thread.js");

View File

@ -33,6 +33,7 @@ import org.teavm.ast.NewArrayExpr;
import org.teavm.ast.NewExpr;
import org.teavm.ast.NewMultiArrayExpr;
import org.teavm.ast.OperationType;
import org.teavm.ast.PrimitiveCastExpr;
import org.teavm.ast.QualificationExpr;
import org.teavm.ast.RecursiveVisitor;
import org.teavm.ast.RegularMethodNode;
@ -209,6 +210,65 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
@Override
public void visit(BinaryExpr expr) {
super.visit(expr);
if (expr.getType() == OperationType.LONG) {
switch (expr.getOperation()) {
case ADD:
consumer.consumeFunction("Long_add");
break;
case SUBTRACT:
consumer.consumeFunction("Long_sub");
break;
case MULTIPLY:
consumer.consumeFunction("Long_mul");
break;
case DIVIDE:
consumer.consumeFunction("Long_div");
break;
case MODULO:
consumer.consumeFunction("Long_rem");
break;
case BITWISE_OR:
consumer.consumeFunction("Long_or");
break;
case BITWISE_AND:
consumer.consumeFunction("Long_and");
break;
case BITWISE_XOR:
consumer.consumeFunction("Long_xor");
break;
case LEFT_SHIFT:
consumer.consumeFunction("Long_shl");
break;
case RIGHT_SHIFT:
consumer.consumeFunction("Long_shr");
break;
case UNSIGNED_RIGHT_SHIFT:
consumer.consumeFunction("Long_shru");
break;
case COMPARE:
consumer.consumeFunction("Long_compare");
break;
case EQUALS:
consumer.consumeFunction("Long_eq");
break;
case NOT_EQUALS:
consumer.consumeFunction("Long_ne");
break;
case LESS:
consumer.consumeFunction("Long_lt");
break;
case LESS_OR_EQUALS:
consumer.consumeFunction("Long_le");
break;
case GREATER:
consumer.consumeFunction("Long_gt");
break;
case GREATER_OR_EQUALS:
consumer.consumeFunction("Long_ge");
break;
}
return;
}
switch (expr.getOperation()) {
case COMPARE:
consumer.consumeFunction("$rt_compare");
@ -231,17 +291,56 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
case NULL_CHECK:
consumer.consumeFunction("$rt_nullCheck");
break;
case NEGATE:
if (expr.getType() == OperationType.LONG) {
consumer.consumeFunction("Long_neg");
}
break;
case NOT:
if (expr.getType() == OperationType.LONG) {
consumer.consumeFunction("Long_not");
}
break;
default:
break;
}
}
@Override
public void visit(PrimitiveCastExpr expr) {
super.visit(expr);
if (expr.getSource() == OperationType.LONG) {
if (expr.getTarget() == OperationType.DOUBLE || expr.getTarget() == OperationType.FLOAT) {
consumer.consumeFunction("Long_toNumber");
}
} else {
switch (expr.getSource()) {
case INT:
consumer.consumeFunction("Long_fromInt");
break;
case FLOAT:
case DOUBLE:
consumer.consumeFunction("Long_fromNUmber");
break;
}
}
}
@Override
public void visit(ConstantExpr expr) {
if (expr.getValue() instanceof ValueType) {
visitType((ValueType) expr.getValue());
} else if (expr.getValue() instanceof String) {
consumer.consumeFunction("$rt_s");
} else if (expr.getValue() instanceof Long) {
long value = (Long) expr.getValue();
if (value == 0) {
consumer.consumeFunction("Long_ZERO");
} else if ((int) value == value) {
consumer.consumeFunction("Long_fromInt");
} else {
consumer.consumeFunction("Long");
}
}
}
@ -291,7 +390,34 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
public void visit(NewArrayExpr expr) {
super.visit(expr);
visitType(expr.getType());
if (!(expr.getType() instanceof ValueType.Primitive)) {
if (expr.getType() instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) expr.getType()).getKind()) {
case BOOLEAN:
consumer.consumeFunction("$rt_createBooleanArray");
break;
case BYTE:
consumer.consumeFunction("$rt_createByteArray");
break;
case SHORT:
consumer.consumeFunction("$rt_createShortArray");
break;
case CHARACTER:
consumer.consumeFunction("$rt_createCharArray");
break;
case INTEGER:
consumer.consumeFunction("$rt_createIntArray");
break;
case LONG:
consumer.consumeFunction("$rt_createLongArray");
break;
case FLOAT:
consumer.consumeFunction("$rt_createFloatArray");
break;
case DOUBLE:
consumer.consumeFunction("$rt_createDoubleArray");
break;
}
} else {
consumer.consumeFunction("$rt_createArray");
}
}

View File

@ -249,8 +249,8 @@ public class Renderer implements RenderingManager {
sizeByClass.put(className, sizeByClass.getOrDefault(className, 0) + sz);
}
private void renderRuntimeAliases() throws IOException {
String[] names = { "$rt_throw", "$rt_compare", "$rt_nullCheck", "$rt_cls", "$rt_createArray",
private void renderCommonRuntimeAliases() throws IOException {
renderRuntimeAliases("$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_imul", "$rt_wrapException", "$rt_checkBounds",
"$rt_checkUpperBound", "$rt_checkLowerBound", "$rt_wrapFunction0", "$rt_wrapFunction1",
@ -258,7 +258,19 @@ public class Renderer implements RenderingManager {
"$rt_classWithoutFields", "$rt_createArrayFromData", "$rt_createCharArrayFromData",
"$rt_createByteArrayFromData", "$rt_createShortArrayFromData", "$rt_createIntArrayFromData",
"$rt_createBooleanArrayFromData", "$rt_createFloatArrayFromData", "$rt_createDoubleArrayFromData",
"$rt_createLongArrayFromData" };
"$rt_createLongArrayFromData", "$rt_createBooleanArray", "$rt_createByteArray",
"$rt_createShortArray", "$rt_createCharArray", "$rt_createIntArray", "$rt_createLongArray",
"$rt_createFloatArray", "$rt_createDoubleArray", "$rt_compare",
"Long_toNumber", "Long_fromInt", "Long_fromNumber", "Long", "Long_ZERO");
}
public void renderLongRuntimeAliases() throws IOException {
renderRuntimeAliases("Long_add", "Long_sub", "Long_mul", "Long_div", "Long_rem", "Long_or", "Long_and",
"Long_xor", "Long_shl", "Long_shr", "Long_shru", "Long_compare", "Long_eq", "Long_ne",
"Long_lt", "Long_le", "Long_gt", "Long_ge", "Long_not", "Long_neg");
}
private void renderRuntimeAliases(String... names) throws IOException {
boolean first = true;
for (String name : names) {
if (!first) {
@ -286,7 +298,7 @@ public class Renderer implements RenderingManager {
public boolean render(List<PreparedClass> classes) throws RenderingException {
if (minifying) {
try {
renderRuntimeAliases();
renderCommonRuntimeAliases();
} catch (IOException e) {
throw new RenderingException(e);
}

View File

@ -235,11 +235,12 @@ public class RenderingContext {
} else if (cst instanceof Long) {
long value = (Long) cst;
if (value == 0) {
writer.append("Long_ZERO");
writer.appendFunction("Long_ZERO");
} else if ((int) value == value) {
writer.append("Long_fromInt(" + value + ")");
writer.appendFunction("Long_fromInt").append("(").append(String.valueOf(value)).append(")");
} else {
writer.append("new Long(" + (value & 0xFFFFFFFFL) + ", " + (value >>> 32) + ")");
writer.append("new ").appendFunction("Long").append("(" + (value & 0xFFFFFFFFL)
+ ", " + (value >>> 32) + ")");
}
} else if (cst instanceof Character) {
writer.append(Integer.toString((Character) cst));

View File

@ -644,7 +644,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
if (expr.getLocation() != null) {
pushLocation(expr.getLocation());
}
writer.append(function);
writer.appendFunction(function);
writer.append('(');
precedence = Precedence.min();
expr.getFirstOperand().acceptVisitor(this);
@ -656,7 +656,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
popLocation();
}
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
throw new RenderingException("IO error occurred", e);
}
}
@ -735,7 +735,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|| RenderingUtil.isSmallInteger(expr.getSecondOperand())) {
visitBinary(expr, "*", expr.getType() == OperationType.INT);
} else {
visitBinaryFunction(expr, naming.getNameForFunction("$rt_imul"));
visitBinaryFunction(expr, "$rt_imul");
}
break;
case DIVIDE:
@ -771,7 +771,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
visitBinary(expr, "<=", false);
break;
case COMPARE:
visitBinaryFunction(expr, naming.getNameForFunction("$rt_compare"));
visitBinaryFunction(expr, "$rt_compare");
break;
case OR:
visitBinary(expr, "||", false);
@ -812,7 +812,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
case NOT: {
if (expr.getType() == OperationType.LONG) {
longLibraryUsed = true;
writer.append("Long_not(");
writer.appendFunction("Long_not").append("(");
precedence = Precedence.min();
expr.getOperand().acceptVisitor(this);
writer.append(')');
@ -832,7 +832,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
case NEGATE:
if (expr.getType() == OperationType.LONG) {
longLibraryUsed = true;
writer.append("Long_neg(");
writer.appendFunction("Long_neg").append("(");
precedence = Precedence.min();
expr.getOperand().acceptVisitor(this);
writer.append(')');
@ -897,7 +897,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
popLocation();
}
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
throw new RenderingException("IO error occurred", e);
}
}
@ -915,7 +915,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
switch (expr.getSource()) {
case INT:
if (expr.getTarget() == OperationType.LONG) {
writer.append("Long_fromInt(");
writer.appendFunction("Long_fromInt").append("(");
precedence = Precedence.min();
expr.getValue().acceptVisitor(this);
writer.append(')');
@ -938,7 +938,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
break;
case FLOAT:
case DOUBLE:
writer.append("Long_toNumber(");
writer.appendFunction("Long_toNumber").append("(");
precedence = Precedence.min();
expr.getValue().acceptVisitor(this);
writer.append(')');
@ -951,7 +951,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
case DOUBLE:
switch (expr.getTarget()) {
case LONG:
writer.append("Long_fromNumber(");
writer.appendFunction("Long_fromNumber").append("(");
precedence = Precedence.min();
expr.getValue().acceptVisitor(this);
writer.append(')');
@ -975,7 +975,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
popLocation();
}
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
throw new RenderingException("IO error occurred", e);
}
}
@ -1033,7 +1033,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
popLocation();
}
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
throw new RenderingException("IO error occurred", e);
}
}
@ -1048,7 +1048,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
popLocation();
}
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
throw new RenderingException("IO error occurred", e);
}
}
@ -1063,7 +1063,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
popLocation();
}
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
throw new RenderingException("IO error occurred", e);
}
}
@ -1263,49 +1263,49 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN:
writer.append("$rt_createBooleanArray(");
writer.appendFunction("$rt_createBooleanArray").append("(");
precedence = Precedence.min();
expr.getLength().acceptVisitor(this);
writer.append(")");
break;
case BYTE:
writer.append("$rt_createByteArray(");
writer.appendFunction("$rt_createByteArray").append("(");
precedence = Precedence.min();
expr.getLength().acceptVisitor(this);
writer.append(")");
break;
case SHORT:
writer.append("$rt_createShortArray(");
writer.appendFunction("$rt_createShortArray").append("(");
precedence = Precedence.min();
expr.getLength().acceptVisitor(this);
writer.append(")");
break;
case INTEGER:
writer.append("$rt_createIntArray(");
writer.appendFunction("$rt_createIntArray").append("(");
precedence = Precedence.min();
expr.getLength().acceptVisitor(this);
writer.append(")");
break;
case LONG:
writer.append("$rt_createLongArray(");
writer.appendFunction("$rt_createLongArray").append("(");
precedence = Precedence.min();
expr.getLength().acceptVisitor(this);
writer.append(")");
break;
case FLOAT:
writer.append("$rt_createFloatArray(");
writer.appendFunction("$rt_createFloatArray").append("(");
precedence = Precedence.min();
expr.getLength().acceptVisitor(this);
writer.append(")");
break;
case DOUBLE:
writer.append("$rt_createDoubleArray(");
writer.appendFunction("$rt_createDoubleArray").append("(");
precedence = Precedence.min();
expr.getLength().acceptVisitor(this);
writer.append(")");
break;
case CHARACTER:
writer.append("$rt_createCharArray(");
writer.appendFunction("$rt_createCharArray").append("(");
precedence = Precedence.min();
expr.getLength().acceptVisitor(this);
writer.append(")");

View File

@ -295,6 +295,9 @@ function Long_shru(a, b) {
return new Long((a.hi >>> (b - 32)), 0);
}
}
function Long_not(a) {
return new Long(~a.hi, ~a.lo);
}
// Represents a mutable 80-bit unsigned integer
function LongInt(lo, hi, sup) {