From 62118e2cfe7e7d697c922e9e6c07d360cd9e8e7b Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Mon, 9 Mar 2015 13:28:37 +0300 Subject: [PATCH] Add frequency-based naming in minified mode --- .../lang/reflect/ArrayNativeGenerator.java | 2 +- .../java/org/teavm/codegen/AliasProvider.java | 3 + .../teavm/codegen/DefaultAliasProvider.java | 13 + .../teavm/codegen/DefaultNamingStrategy.java | 10 +- .../teavm/codegen/MinifyingAliasProvider.java | 17 +- .../teavm/codegen/NameFrequencyConsumer.java | 40 ++ .../java/org/teavm/codegen/NamingOrderer.java | 162 ++++++++ .../org/teavm/codegen/NamingStrategy.java | 5 +- .../java/org/teavm/codegen/SourceWriter.java | 12 +- .../javascript/NameFrequencyEstimator.java | 347 ++++++++++++++++++ .../java/org/teavm/javascript/Renderer.java | 18 +- .../src/main/java/org/teavm/vm/TeaVM.java | 3 +- .../teavm/html4j/JavaScriptBodyGenerator.java | 2 +- .../teavm/jso/plugin/JSOAliasRenderer.java | 4 +- .../platform/plugin/AsyncMethodGenerator.java | 8 +- ...ScopedMetadataProviderNativeGenerator.java | 2 +- 16 files changed, 614 insertions(+), 34 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/codegen/NameFrequencyConsumer.java create mode 100644 teavm-core/src/main/java/org/teavm/codegen/NamingOrderer.java create mode 100644 teavm-core/src/main/java/org/teavm/javascript/NameFrequencyEstimator.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java index 468334f63..ed9a46d5c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java @@ -73,7 +73,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin { writer.append("if (" + array + " === null || " + array + ".constructor.$meta.item === undefined) {") .softNewLine().indent(); String clsName = "java.lang.IllegalArgumentException"; - MethodReference cons = new MethodReference(clsName, new MethodDescriptor("", ValueType.VOID)); + MethodDescriptor cons = new MethodDescriptor("", ValueType.VOID); writer.append("$rt_throw(").appendClass(clsName).append(".").appendMethod(cons).append("());").softNewLine(); writer.outdent().append("}").softNewLine(); writer.append("return " + array + ".data.length;").softNewLine(); diff --git a/teavm-core/src/main/java/org/teavm/codegen/AliasProvider.java b/teavm-core/src/main/java/org/teavm/codegen/AliasProvider.java index 0f521f5e3..28a615277 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/AliasProvider.java +++ b/teavm-core/src/main/java/org/teavm/codegen/AliasProvider.java @@ -16,6 +16,7 @@ package org.teavm.codegen; import org.teavm.model.FieldReference; +import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; /** @@ -27,5 +28,7 @@ public interface AliasProvider { String getAlias(MethodReference method); + String getAlias(MethodDescriptor method); + String getAlias(String className); } diff --git a/teavm-core/src/main/java/org/teavm/codegen/DefaultAliasProvider.java b/teavm-core/src/main/java/org/teavm/codegen/DefaultAliasProvider.java index 22d4a5f7e..9b66e6cca 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/DefaultAliasProvider.java +++ b/teavm-core/src/main/java/org/teavm/codegen/DefaultAliasProvider.java @@ -16,6 +16,7 @@ package org.teavm.codegen; import org.teavm.model.FieldReference; +import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; /** @@ -24,6 +25,7 @@ import org.teavm.model.MethodReference; */ public class DefaultAliasProvider implements AliasProvider { private int lastSuffix; + private int lastVirtualSuffix; @Override public String getAlias(String cls) { @@ -48,6 +50,17 @@ public class DefaultAliasProvider implements AliasProvider { return alias.toString(); } + @Override + public String getAlias(MethodDescriptor method) { + String alias = method.getName(); + if (alias.equals("")) { + alias = "$init"; + } else if (alias.equals("")) { + alias = "$clinit"; + } + return alias + lastVirtualSuffix++; + } + @Override public String getAlias(MethodReference method) { String alias = method.getDescriptor().getName(); diff --git a/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java b/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java index db4209c51..f977b3a33 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java +++ b/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java @@ -56,17 +56,17 @@ public class DefaultNamingStrategy implements NamingStrategy { } @Override - public String getNameFor(MethodReference method) { + public String getNameFor(MethodDescriptor method) { return getNameFor(method, 'S'); } @Override - public String getNameForAsync(MethodReference method) throws NamingException { + public String getNameForAsync(MethodDescriptor method) throws NamingException { return getNameFor(method, 'A'); } - private String getNameFor(MethodReference method, char classifier) { - String key = classifier + method.getDescriptor().toString(); + private String getNameFor(MethodDescriptor method, char classifier) { + String key = classifier + method.toString(); String alias = aliases.get(key); if (alias == null) { alias = aliasProvider.getAlias(method); @@ -97,7 +97,7 @@ public class DefaultNamingStrategy implements NamingStrategy { throw new NamingException("Can't provide name for method as it was not found: " + originalMethod); } if (!minifying) { - return getNameFor(method.getClassName()) + "_" + getNameFor(method, classifier); + return getNameFor(method.getClassName()) + "_" + getNameFor(method.getDescriptor(), classifier); } String key = classifier + method.toString(); String alias = privateAliases.get(key); diff --git a/teavm-core/src/main/java/org/teavm/codegen/MinifyingAliasProvider.java b/teavm-core/src/main/java/org/teavm/codegen/MinifyingAliasProvider.java index 4f8e83d44..1410f3991 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/MinifyingAliasProvider.java +++ b/teavm-core/src/main/java/org/teavm/codegen/MinifyingAliasProvider.java @@ -16,6 +16,7 @@ package org.teavm.codegen; import org.teavm.model.FieldReference; +import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; /** @@ -25,25 +26,31 @@ import org.teavm.model.MethodReference; public class MinifyingAliasProvider implements AliasProvider { private static String startLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static String startVirtualLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; private int lastSuffix; + private int lastVirtual; @Override public String getAlias(FieldReference field) { - return getNewAlias(); + return getNewAlias(lastVirtual++, startVirtualLetters); } @Override public String getAlias(MethodReference method) { - return getNewAlias(); + return getNewAlias(lastSuffix++, startLetters); + } + + @Override + public String getAlias(MethodDescriptor method) { + return getNewAlias(lastVirtual++, startVirtualLetters); } @Override public String getAlias(String className) { - return getNewAlias(); + return getNewAlias(lastSuffix++, startLetters); } - private String getNewAlias() { - int index = lastSuffix++; + private String getNewAlias(int index, String startLetters) { StringBuilder sb = new StringBuilder(); sb.append(startLetters.charAt(index % startLetters.length())); index /= startLetters.length(); diff --git a/teavm-core/src/main/java/org/teavm/codegen/NameFrequencyConsumer.java b/teavm-core/src/main/java/org/teavm/codegen/NameFrequencyConsumer.java new file mode 100644 index 000000000..bfa6cfaab --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/codegen/NameFrequencyConsumer.java @@ -0,0 +1,40 @@ +/* + * Copyright 2015 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.codegen; + +import org.teavm.model.FieldReference; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +public interface NameFrequencyConsumer { + void consume(MethodReference method); + + void consumeAsync(MethodReference method); + + void consumeInit(MethodReference method); + + void consume(MethodDescriptor method); + + void consumeAsync(MethodDescriptor method); + + void consume(String className); + + void consume(FieldReference field); +} diff --git a/teavm-core/src/main/java/org/teavm/codegen/NamingOrderer.java b/teavm-core/src/main/java/org/teavm/codegen/NamingOrderer.java new file mode 100644 index 000000000..1ab640f3e --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/codegen/NamingOrderer.java @@ -0,0 +1,162 @@ +/* + * Copyright 2015 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.codegen; + +import java.util.*; +import org.teavm.model.FieldReference; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +public class NamingOrderer implements NameFrequencyConsumer { + private Map entries = new HashMap<>(); + + @Override + public void consume(final MethodReference method) { + String key = "R:" + method; + Entry entry = entries.get(key); + if (entry == null) { + entry = new Entry(); + entry.operation = new NamingOperation() { + @Override public void perform(NamingStrategy naming) { + naming.getFullNameFor(method); + } + }; + entries.put(key, entry); + } + entry.frequency++; + } + + @Override + public void consumeAsync(final MethodReference method) { + String key = "A:" + method; + Entry entry = entries.get(key); + if (entry == null) { + entry = new Entry(); + entry.operation = new NamingOperation() { + @Override public void perform(NamingStrategy naming) { + naming.getFullNameForAsync(method); + } + }; + entries.put(key, entry); + } + entry.frequency++; + } + + @Override + public void consumeInit(final MethodReference method) { + String key = "I:" + method; + Entry entry = entries.get(key); + if (entry == null) { + entry = new Entry(); + entry.operation = new NamingOperation() { + @Override public void perform(NamingStrategy naming) { + naming.getNameForInit(method); + } + }; + entries.put(key, entry); + } + entry.frequency++; + } + + @Override + public void consume(final MethodDescriptor method) { + String key = "r:" + method; + Entry entry = entries.get(key); + if (entry == null) { + entry = new Entry(); + entry.operation = new NamingOperation() { + @Override public void perform(NamingStrategy naming) { + naming.getNameFor(method); + } + }; + entries.put(key, entry); + } + entry.frequency++; + } + + @Override + public void consumeAsync(final MethodDescriptor method) { + String key = "a:" + method; + Entry entry = entries.get(key); + if (entry == null) { + entry = new Entry(); + entry.operation = new NamingOperation() { + @Override public void perform(NamingStrategy naming) { + naming.getNameForAsync(method); + } + }; + entries.put(key, entry); + } + entry.frequency++; + } + + @Override + public void consume(final String className) { + String key = "c:" + className; + Entry entry = entries.get(key); + if (entry == null) { + entry = new Entry(); + entry.operation = new NamingOperation() { + @Override public void perform(NamingStrategy naming) { + naming.getNameFor(className); + } + }; + entries.put(key, entry); + } + entry.frequency++; + } + + @Override + public void consume(final FieldReference field) { + String key = "f:" + field; + Entry entry = entries.get(key); + if (entry == null) { + entry = new Entry(); + entry.operation = new NamingOperation() { + @Override public void perform(NamingStrategy naming) { + naming.getNameFor(field); + } + }; + entries.put(key, entry); + } + entry.frequency++; + } + + public void apply(NamingStrategy naming) { + List entryList = new ArrayList<>(entries.values()); + Collections.sort(entryList, new Comparator() { + @Override public int compare(Entry o1, Entry o2) { + return Integer.compare(o2.frequency, o1.frequency); + } + }); + for (Entry entry : entryList) { + entry.operation.perform(naming); + } + } + + static class Entry { + NamingOperation operation; + int frequency; + } + + interface NamingOperation { + void perform(NamingStrategy naming); + } +} diff --git a/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java b/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java index 0851c0b78..bbdd476e7 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java +++ b/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java @@ -16,6 +16,7 @@ package org.teavm.codegen; import org.teavm.model.FieldReference; +import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; /** @@ -25,9 +26,9 @@ import org.teavm.model.MethodReference; public interface NamingStrategy { String getNameFor(String cls) throws NamingException; - String getNameFor(MethodReference method) throws NamingException; + String getNameFor(MethodDescriptor method) throws NamingException; - String getNameForAsync(MethodReference method) throws NamingException; + String getNameForAsync(MethodDescriptor method) throws NamingException; String getNameForInit(MethodReference method) throws NamingException; diff --git a/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java b/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java index a1ced11f0..4be2811cb 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java +++ b/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java @@ -111,18 +111,16 @@ public class SourceWriter implements Appendable, LocationProvider { return append(naming.getNameFor(field)); } - public SourceWriter appendMethod(MethodReference method) throws NamingException, IOException { + public SourceWriter appendMethod(MethodDescriptor method) throws NamingException, IOException { return append(naming.getNameFor(method)); } - public SourceWriter appendMethod(String className, String name, ValueType... params) - throws NamingException, IOException { - return append(naming.getNameFor(new MethodReference(className, name, params))); + public SourceWriter appendMethod(String name, ValueType... params) throws NamingException, IOException { + return append(naming.getNameFor(new MethodDescriptor(name, params))); } - public SourceWriter appendMethod(Class cls, String name, Class... params) - throws NamingException, IOException { - return append(naming.getNameFor(new MethodReference(cls, name, params))); + public SourceWriter appendMethod(String name, Class... params) throws NamingException, IOException { + return append(naming.getNameFor(new MethodDescriptor(name, params))); } public SourceWriter appendMethodBody(MethodReference method) throws NamingException, IOException { diff --git a/teavm-core/src/main/java/org/teavm/javascript/NameFrequencyEstimator.java b/teavm-core/src/main/java/org/teavm/javascript/NameFrequencyEstimator.java new file mode 100644 index 000000000..c68a4b9e8 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/javascript/NameFrequencyEstimator.java @@ -0,0 +1,347 @@ +/* + * Copyright 2015 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.javascript; + +import java.util.List; +import java.util.Set; +import org.teavm.codegen.NameFrequencyConsumer; +import org.teavm.javascript.ast.*; +import org.teavm.model.*; + +/** + * + * @author Alexey Andreev + */ +public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, MethodNodeVisitor { + private NameFrequencyConsumer consumer; + private ClassReaderSource classSource; + private boolean async; + private Set injectedMethods; + private Set asyncFamilyMethods; + + public NameFrequencyEstimator(NameFrequencyConsumer consumer, ClassReaderSource classSource, + Set injectedMethods, Set asyncFamilyMethods) { + this.consumer = consumer; + this.classSource = classSource; + this.injectedMethods = injectedMethods; + this.asyncFamilyMethods = asyncFamilyMethods; + } + + private void visit(List statements) { + for (Statement part : statements) { + part.acceptVisitor(this); + } + } + + public void estimate(ClassNode cls) { + // Declaration + consumer.consume(cls.getName()); + if (cls.getParentName() != null) { + consumer.consume(cls.getParentName()); + } + for (FieldNode field : cls.getFields()) { + consumer.consume(new FieldReference(cls.getName(), field.getName())); + if (field.getModifiers().contains(NodeModifier.STATIC)) { + consumer.consume(cls.getName()); + } + } + + // Methods + MethodReader clinit = classSource.get(cls.getName()).getMethod( + new MethodDescriptor("", ValueType.VOID)); + for (MethodNode method : cls.getMethods()) { + if (method.isAsync()) { + consumer.consumeAsync(method.getReference()); + } else { + consumer.consume(method.getReference()); + if (asyncFamilyMethods.contains(method.getReference())) { + consumer.consume(method.getReference()); + consumer.consumeAsync(method.getReference()); + } + } + if (clinit != null && (method.getModifiers().contains(NodeModifier.STATIC) || + method.getReference().getName().equals(""))) { + if (!method.isAsync()) { + consumer.consume(method.getReference()); + } + if (asyncFamilyMethods.contains(method.getReference())) { + consumer.consumeAsync(method.getReference()); + } + } + if (!method.getModifiers().contains(NodeModifier.STATIC)) { + if (method.isAsync()) { + consumer.consumeAsync(method.getReference().getDescriptor()); + consumer.consumeAsync(method.getReference()); + } else { + consumer.consume(method.getReference().getDescriptor()); + consumer.consume(method.getReference()); + if (asyncFamilyMethods.contains(method.getReference())) { + consumer.consumeAsync(method.getReference().getDescriptor()); + consumer.consumeAsync(method.getReference()); + } + } + } + } + + // Metadata + consumer.consume(cls.getName()); + consumer.consume(cls.getName()); + if (cls.getParentName() != null) { + consumer.consume(cls.getParentName()); + } + for (String iface : cls.getInterfaces()) { + consumer.consume(iface); + } + } + + @Override + public void visit(RegularMethodNode methodNode) { + async = false; + methodNode.getBody().acceptVisitor(this); + } + + @Override + public void visit(AsyncMethodNode methodNode) { + async = true; + for (AsyncMethodPart part : methodNode.getBody()) { + part.getStatement().acceptVisitor(this); + } + } + + @Override + public void visit(NativeMethodNode methodNode) { + } + + @Override + public void visit(AssignmentStatement statement) { + if (statement.getLeftValue() != null) { + statement.getLeftValue().acceptVisitor(this); + } + statement.getRightValue().acceptVisitor(this); + } + + @Override + public void visit(SequentialStatement statement) { + visit(statement.getSequence()); + } + + @Override + public void visit(ConditionalStatement statement) { + statement.getCondition().acceptVisitor(this); + visit(statement.getConsequent()); + visit(statement.getAlternative()); + } + + @Override + public void visit(SwitchStatement statement) { + statement.getValue().acceptVisitor(this); + for (SwitchClause clause : statement.getClauses()) { + visit(clause.getBody()); + } + visit(statement.getDefaultClause()); + } + + @Override + public void visit(WhileStatement statement) { + if (statement.getCondition() != null) { + statement.getCondition().acceptVisitor(this); + } + visit(statement.getBody()); + } + + @Override + public void visit(BlockStatement statement) { + visit(statement.getBody()); + } + + @Override + public void visit(BreakStatement statement) { + } + + @Override + public void visit(ContinueStatement statement) { + } + + @Override + public void visit(ReturnStatement statement) { + if (statement.getResult() != null) { + statement.getResult().acceptVisitor(this); + } + } + + @Override + public void visit(ThrowStatement statement) { + statement.getException().acceptVisitor(this); + } + + @Override + public void visit(InitClassStatement statement) { + consumer.consume(statement.getClassName()); + } + + @Override + public void visit(TryCatchStatement statement) { + visit(statement.getProtectedBody()); + visit(statement.getHandler()); + if (statement.getExceptionType() != null) { + consumer.consume(statement.getExceptionType()); + } + } + + @Override + public void visit(RestoreAsyncStatement statement) { + } + + @Override + public void visit(MonitorEnterStatement statement) { + if (async) { + MethodReference monitorEnterRef = new MethodReference( + Object.class, "monitorEnter", Object.class, void.class); + consumer.consumeAsync(monitorEnterRef); + } else { + MethodReference monitorEnterRef = new MethodReference( + Object.class, "monitorEnterSync", Object.class, void.class); + consumer.consume(monitorEnterRef); + } + } + + @Override + public void visit(MonitorExitStatement statement) { + if (async) { + MethodReference monitorEnterRef = new MethodReference( + Object.class, "monitorExit", Object.class, void.class); + consumer.consumeAsync(monitorEnterRef); + } else { + MethodReference monitorEnterRef = new MethodReference( + Object.class, "monitorExitSync", Object.class, void.class); + consumer.consume(monitorEnterRef); + } + } + + @Override + public void visit(BinaryExpr expr) { + expr.getFirstOperand().acceptVisitor(this); + expr.getSecondOperand().acceptVisitor(this); + } + + @Override + public void visit(UnaryExpr expr) { + expr.getOperand().acceptVisitor(this); + } + + @Override + public void visit(ConditionalExpr expr) { + expr.getCondition().acceptVisitor(this); + expr.getConsequent().acceptVisitor(this); + expr.getAlternative().acceptVisitor(this); + } + + @Override + public void visit(ConstantExpr expr) { + if (expr.getValue() instanceof ValueType) { + visitType((ValueType)expr.getValue()); + } + } + + private void visitType(ValueType type) { + while (type instanceof ValueType.Array) { + type = ((ValueType.Array)type).getItemType(); + } + if (type instanceof ValueType.Object) { + String clsName = ((ValueType.Object)type).getClassName(); + consumer.consume(clsName); + } + } + + @Override + public void visit(VariableExpr expr) { + } + + @Override + public void visit(SubscriptExpr expr) { + expr.getArray().acceptVisitor(this); + expr.getIndex().acceptVisitor(this); + } + + @Override + public void visit(UnwrapArrayExpr expr) { + expr.getArray().acceptVisitor(this); + } + + @Override + public void visit(InvocationExpr expr) { + if (injectedMethods.contains(expr.getMethod())) { + return; + } + boolean asyncCall = expr.getAsyncTarget() != null; + switch (expr.getType()) { + case SPECIAL: + case STATIC: + if (asyncCall) { + consumer.consumeAsync(expr.getMethod()); + } else { + consumer.consume(expr.getMethod()); + } + break; + case CONSTRUCTOR: + consumer.consumeInit(expr.getMethod()); + break; + case DYNAMIC: + if (asyncCall) { + consumer.consumeAsync(expr.getMethod().getDescriptor()); + } else { + consumer.consume(expr.getMethod().getDescriptor()); + } + break; + } + } + + @Override + public void visit(QualificationExpr expr) { + expr.getQualified().acceptVisitor(this); + consumer.consume(expr.getField()); + } + + @Override + public void visit(NewExpr expr) { + consumer.consume(expr.getConstructedClass()); + } + + @Override + public void visit(NewArrayExpr expr) { + visitType(expr.getType()); + expr.getLength().acceptVisitor(this); + } + + @Override + public void visit(NewMultiArrayExpr expr) { + visitType(expr.getType()); + for (Expr dimension : expr.getDimensions()) { + dimension.acceptVisitor(this); + } + } + + @Override + public void visit(InstanceOfExpr expr) { + expr.getExpr().acceptVisitor(this); + visitType(expr.getType()); + } + + @Override + public void visit(StaticClassExpr expr) { + visitType(expr.getType()); + } +} 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 5c240ecfd..c205a34f8 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -20,6 +20,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.*; import org.teavm.codegen.NamingException; +import org.teavm.codegen.NamingOrderer; import org.teavm.codegen.NamingStrategy; import org.teavm.codegen.SourceWriter; import org.teavm.common.ServiceRepository; @@ -259,6 +260,15 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } public void render(List classes) throws RenderingException { + if (minifying) { + NamingOrderer orderer = new NamingOrderer(); + NameFrequencyEstimator estimator = new NameFrequencyEstimator(orderer, classSource, asyncMethods, + asyncFamilyMethods); + for (ClassNode cls : classes) { + estimator.estimate(cls); + } + orderer.apply(naming); + } for (ClassNode cls : classes) { renderDeclaration(cls); } @@ -313,7 +323,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext .append(constantToString(value)).append(";").softNewLine(); } } catch (NamingException e) { - throw new RenderingException("Error rendering class " + cls.getName() + ". See a cause for details", e); + throw new RenderingException("Error rendering class " + cls.getName() + ". See cause for details", e); } catch (IOException e) { throw new RenderingException("IO error occured", e); } @@ -529,7 +539,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } private void emitVirtualDeclaration(MethodReference ref, boolean async) throws IOException { - String methodName = async ? naming.getNameForAsync(ref) : naming.getNameFor(ref); + String methodName = async ? naming.getNameForAsync(ref.getDescriptor()) : + naming.getNameFor(ref.getDescriptor()); writer.append("\"").append(methodName).append("\""); writer.append(",").ws().append("function("); List args = new ArrayList<>(); @@ -1665,7 +1676,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext expr.getArguments().get(0).acceptVisitor(this); } MethodReference method = expr.getMethod(); - String name = asyncCall ? naming.getNameForAsync(method) : naming.getNameFor(method); + String name = asyncCall ? naming.getNameForAsync(method.getDescriptor()) : + naming.getNameFor(method.getDescriptor()); DeferredCallSite callSite = prevCallSite; boolean shouldEraseCallSite = lastCallSite == null; if (lastCallSite == null) { diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index f459e4a46..6d6912b45 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -549,12 +549,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository { for (MethodReference injectedMethod : methodInjectors.keySet()) { decompiler.addMethodToPass(injectedMethod); } - List classOrder = decompiler.getClassOrdering(classes.getClassNames()); List classNodes = new ArrayList<>(); int index = 0; try (PrintWriter bytecodeLogger = bytecodeLogging ? new PrintWriter(new OutputStreamWriter(logStream, "UTF-8")) : null) { - for (String className : classOrder) { + for (String className : classes.getClassNames()) { ClassHolder cls = classes.get(className); for (MethodHolder method : cls.getMethods()) { processMethod(method); diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java index e7ba4e610..9d22c3cd8 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java @@ -99,7 +99,7 @@ public class JavaScriptBodyGenerator implements Generator { if (ident == null) { sb.append(naming.getFullNameFor(reader.getReference())); } else { - sb.append("$this.").append(naming.getNameFor(reader.getReference())); + sb.append("$this.").append(naming.getNameFor(reader.getDescriptor())); } sb.append("("); for (int i = 0; i < reader.parameterCount(); ++i) { diff --git a/teavm-jso/src/main/java/org/teavm/jso/plugin/JSOAliasRenderer.java b/teavm-jso/src/main/java/org/teavm/jso/plugin/JSOAliasRenderer.java index a6c7aec9f..04c76fdf2 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/plugin/JSOAliasRenderer.java +++ b/teavm-jso/src/main/java/org/teavm/jso/plugin/JSOAliasRenderer.java @@ -21,7 +21,6 @@ import org.teavm.codegen.SourceWriter; import org.teavm.javascript.RenderingContext; import org.teavm.jso.plugin.JSODependencyListener.ExposedClass; import org.teavm.model.MethodDescriptor; -import org.teavm.model.MethodReference; import org.teavm.vm.BuildTarget; import org.teavm.vm.spi.RendererListener; @@ -57,8 +56,7 @@ class JSOAliasRenderer implements RendererListener { writer.append("c").ws().append("=").ws().appendClass(entry.getKey()).append(".prototype;").softNewLine(); for (Map.Entry aliasEntry : entry.getValue().methods.entrySet()) { writer.append("c.").append(aliasEntry.getValue()).ws().append("=").ws().append("c.") - .appendMethod(new MethodReference(entry.getKey(), aliasEntry.getKey())) - .append(";").softNewLine(); + .appendMethod(aliasEntry.getKey()).append(";").softNewLine(); } } writer.outdent().append("})();").newLine(); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java index e30af413a..c7e4e27bb 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java @@ -39,13 +39,13 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin { public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { MethodReference asyncRef = getAsyncReference(methodRef); writer.append("var callback").ws().append("=").ws().append("function()").ws().append("{};").softNewLine(); - writer.append("callback.").appendMethod(completeMethod).ws().append("=").ws().append("function(val)").ws() - .append("{").indent().softNewLine(); + writer.append("callback.").appendMethod(completeMethod.getDescriptor()).ws().append("=").ws() + .append("function(val)").ws().append("{").indent().softNewLine(); writer.append("return ").append(context.getCompleteContinuation()).append("($rt_asyncResult(val));") .softNewLine(); writer.outdent().append("};").softNewLine(); - writer.append("callback.").appendMethod(errorMethod).ws().append("=").ws().append("function(e)").ws() - .append("{").indent().softNewLine(); + writer.append("callback.").appendMethod(errorMethod.getDescriptor()).ws().append("=").ws() + .append("function(e)").ws().append("{").indent().softNewLine(); writer.append("return ").append(context.getCompleteContinuation()).append("($rt_asyncError(e));") .softNewLine(); writer.outdent().append("};").softNewLine(); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ClassScopedMetadataProviderNativeGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ClassScopedMetadataProviderNativeGenerator.java index cfce5fd15..a41dda509 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ClassScopedMetadataProviderNativeGenerator.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ClassScopedMetadataProviderNativeGenerator.java @@ -80,7 +80,7 @@ public class ClassScopedMetadataProviderNativeGenerator implements Generator { Map resourceMap = generator.generateMetadata(metadataContext, methodRef); writer.append("var p").ws().append("=").ws().append("\"" + Renderer.escapeString("$$res_" + - writer.getNaming().getNameFor(methodRef)) + "\"").append(";").softNewLine(); + writer.getNaming().getFullNameFor(methodRef)) + "\"").append(";").softNewLine(); for (Map.Entry entry : resourceMap.entrySet()) { writer.appendClass(entry.getKey()).append("[p]").ws().append("=").ws(); ResourceWriterHelper.write(writer, entry.getValue());