Various code size optimizations

1. Generate 'a' for 'this' instead of '$t'
2. Fix frequency-based identifier optimization
3. Generate less code in <clinit> callers
4. Generate one-letter identifier in most of constructors
   (instead of $r)
5. Use $ and _ chars in identifiers
This commit is contained in:
Alexey Andreev 2018-10-04 16:29:05 +03:00
parent b66053f5ce
commit 4c4c589172
7 changed files with 26 additions and 17 deletions

View File

@ -318,6 +318,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
} }
int start = sourceWriter.getOffset(); int start = sourceWriter.getOffset();
sourceWriter.append("\"use strict\";").newLine(); sourceWriter.append("\"use strict\";").newLine();
renderer.prepare(clsNodes);
renderer.renderRuntime(); renderer.renderRuntime();
renderer.render(clsNodes); renderer.render(clsNodes);
renderer.renderStringPool(); renderer.renderStringPool();

View File

@ -83,7 +83,7 @@ public class MinifyingAliasProvider implements AliasProvider {
public String getClassInitAlias(String className) { public String getClassInitAlias(String className) {
String result; String result;
do { do {
result = RenderingUtil.indexToId(lastSuffix++, startLetters); result = RenderingUtil.indexToId(lastSuffix++, startLetters);
} while (!usedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result)); } while (!usedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
return result; return result;
} }

View File

@ -100,6 +100,11 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
consumer.consumeFunction("$rt_resuming"); consumer.consumeFunction("$rt_resuming");
consumer.consumeFunction("$rt_invalidPointer"); consumer.consumeFunction("$rt_invalidPointer");
} }
method.acceptVisitor(this);
}
if (clinit != null) {
consumer.consumeFunction("$rt_eraseClinit");
} }
// Metadata // Metadata

View File

@ -295,7 +295,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_s", "$rt_eraseClinit" };
boolean first = true; boolean first = true;
for (String name : names) { for (String name : names) {
if (!first) { if (!first) {
@ -307,7 +307,7 @@ public class Renderer implements RenderingManager {
writer.newLine(); writer.newLine();
} }
public void render(List<ClassNode> classes) throws RenderingException { public void prepare(List<ClassNode> classes) {
if (minifying) { if (minifying) {
NamingOrderer orderer = new NamingOrderer(); NamingOrderer orderer = new NamingOrderer();
NameFrequencyEstimator estimator = new NameFrequencyEstimator(orderer, classSource, asyncMethods, NameFrequencyEstimator estimator = new NameFrequencyEstimator(orderer, classSource, asyncMethods,
@ -317,7 +317,9 @@ public class Renderer implements RenderingManager {
} }
orderer.apply(naming); orderer.apply(naming);
} }
}
public void render(List<ClassNode> classes) throws RenderingException {
if (minifying) { if (minifying) {
try { try {
renderRuntimeAliases(); renderRuntimeAliases();
@ -484,8 +486,8 @@ public class Renderer implements RenderingManager {
private void renderEraseClinit(ClassNode cls) throws IOException { private void renderEraseClinit(ClassNode cls) throws IOException {
writer.append(naming.getNameForClassInit(cls.getName())).ws().append("=").ws() writer.append(naming.getNameForClassInit(cls.getName())).ws().append("=").ws()
.appendClass(cls.getName()).append(".$clinit").ws().append("=").ws() .appendFunction("$rt_eraseClinit").append("(")
.append("function(){};").newLine(); .appendClass(cls.getName()).append(");").softNewLine();
} }
private void renderClassMetadata(List<ClassNode> classes) { private void renderClassMetadata(List<ClassNode> classes) {
@ -713,22 +715,24 @@ public class Renderer implements RenderingManager {
MethodReference ref = method.getReference(); MethodReference ref = method.getReference();
debugEmitter.emitMethod(ref.getDescriptor()); debugEmitter.emitMethod(ref.getDescriptor());
writer.append("function ").append(naming.getNameForInit(ref)).append("("); writer.append("function ").append(naming.getNameForInit(ref)).append("(");
for (int i = 1; i <= ref.parameterCount(); ++i) { for (int i = 0; i < ref.parameterCount(); ++i) {
if (i > 1) { if (i > 0) {
writer.append(",").ws(); writer.append(",").ws();
} }
writer.append(variableNameForInitializer(i)); writer.append(variableNameForInitializer(i));
} }
writer.append(")").ws().append("{").softNewLine().indent(); writer.append(")").ws().append("{").softNewLine().indent();
writer.append("var $r").ws().append("=").ws().append("new ").appendClass(
String instanceName = variableNameForInitializer(ref.parameterCount());
writer.append("var " + instanceName).ws().append("=").ws().append("new ").appendClass(
ref.getClassName()).append("();").softNewLine(); ref.getClassName()).append("();").softNewLine();
writer.append(naming.getFullNameFor(ref)).append("($r"); writer.append(naming.getFullNameFor(ref)).append("(" + instanceName);
for (int i = 1; i <= ref.parameterCount(); ++i) { for (int i = 0; i < ref.parameterCount(); ++i) {
writer.append(",").ws(); writer.append(",").ws();
writer.append(variableNameForInitializer(i)); writer.append(variableNameForInitializer(i));
} }
writer.append(");").softNewLine(); writer.append(");").softNewLine();
writer.append("return $r;").softNewLine(); writer.append("return " + instanceName + ";").softNewLine();
writer.outdent().append("}").newLine(); writer.outdent().append("}").newLine();
debugEmitter.emitMethod(null); debugEmitter.emitMethod(null);
} }

View File

@ -27,7 +27,7 @@ public final class RenderingUtil {
"super", "switch", "this", "throw", "try", "typeof", "var", "void", "while", "with", "yield", "super", "switch", "this", "throw", "try", "typeof", "var", "void", "while", "with", "yield",
"NaN"))); "NaN")));
public static final String VARIABLE_START_CHARS = "abcdefghijklmnopqrstuvwxyz"; public static final String VARIABLE_START_CHARS = "abcdefghijklmnopqrstuvwxyz";
public static final String VARIABLE_PART_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; public static final String VARIABLE_PART_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_";
private RenderingUtil() { private RenderingUtil() {
} }

View File

@ -462,10 +462,6 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
} }
private String generateVariableName(int index) { private String generateVariableName(int index) {
if (index == 0 && minifying) {
return "$t";
}
if (!minifying) { if (!minifying) {
VariableNode variable = index < currentMethod.getVariables().size() VariableNode variable = index < currentMethod.getVariables().size()
? currentMethod.getVariables().get(index) ? currentMethod.getVariables().get(index)
@ -484,7 +480,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
return "var$" + index; return "var$" + index;
} }
} else { } else {
return RenderingUtil.indexToId(--index); return RenderingUtil.indexToId(index);
} }
} }

View File

@ -520,6 +520,9 @@ function $rt_stringPool(strings) {
function $rt_s(index) { function $rt_s(index) {
return $rt_stringPool_instance[index]; return $rt_stringPool_instance[index];
} }
function $rt_eraseClinit(target) {
return target.$clinit = function() {};
}
function TeaVMThread(runner) { function TeaVMThread(runner) {
this.status = 3; this.status = 3;
this.stack = []; this.stack = [];