mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +08:00
JS: add ability to set limit for top-level names.
The purpose of this option is JS engines are too sensible for number of methods in closure, while they don't care about methods in an object.
This commit is contained in:
parent
1214534671
commit
ce13c05342
@ -179,6 +179,8 @@ public class ClassGenerator {
|
||||
tryUsingGenerator(method);
|
||||
}
|
||||
continue;
|
||||
} else if (method.getProgram() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
generateMethodForwardDeclaration(method);
|
||||
|
@ -119,7 +119,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||
private final Set<MethodReference> asyncFamilyMethods = new HashSet<>();
|
||||
private ClassInitializerInsertionTransformer clinitInsertionTransformer;
|
||||
private List<VirtualMethodContributor> customVirtualMethods = new ArrayList<>();
|
||||
private boolean classScoped;
|
||||
private int topLevelNameLimit = 10000;
|
||||
|
||||
@Override
|
||||
public List<ClassHolderTransformer> getTransformers() {
|
||||
return Collections.emptyList();
|
||||
@ -197,8 +198,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||
this.debugEmitter = debugEmitter;
|
||||
}
|
||||
|
||||
public void setClassScoped(boolean classScoped) {
|
||||
this.classScoped = classScoped;
|
||||
public void setTopLevelNameLimit(int topLevelNameLimit) {
|
||||
this.topLevelNameLimit = topLevelNameLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -324,11 +325,12 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||
return;
|
||||
}
|
||||
|
||||
AliasProvider aliasProvider = minifying ? new MinifyingAliasProvider() : new DefaultAliasProvider();
|
||||
AliasProvider aliasProvider = minifying
|
||||
? new MinifyingAliasProvider(topLevelNameLimit)
|
||||
: new DefaultAliasProvider(topLevelNameLimit);
|
||||
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, controller.getUnprocessedClassSource());
|
||||
SourceWriterBuilder builder = new SourceWriterBuilder(naming);
|
||||
builder.setMinified(minifying);
|
||||
builder.setClassScoped(classScoped);
|
||||
SourceWriter sourceWriter = builder.build(writer);
|
||||
|
||||
DebugInformationEmitter debugEmitterToUse = debugEmitter;
|
||||
@ -343,8 +345,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||
controller.getDependencyInfo(), m -> isVirtual(virtualMethodContributorContext, m));
|
||||
renderingContext.setMinifying(minifying);
|
||||
Renderer renderer = new Renderer(sourceWriter, asyncMethods, asyncFamilyMethods,
|
||||
controller.getDiagnostics(), renderingContext, classScoped);
|
||||
RuntimeRenderer runtimeRenderer = new RuntimeRenderer(classes, naming, sourceWriter);
|
||||
controller.getDiagnostics(), renderingContext);
|
||||
RuntimeRenderer runtimeRenderer = new RuntimeRenderer(classes, sourceWriter);
|
||||
renderer.setProperties(controller.getProperties());
|
||||
renderer.setMinifying(minifying);
|
||||
renderer.setProgressConsumer(controller::reportProgress);
|
||||
@ -381,10 +383,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||
|
||||
renderer.prepare(clsNodes);
|
||||
runtimeRenderer.renderRuntime();
|
||||
if (classScoped) {
|
||||
sourceWriter.append("var ").append(Renderer.CONTAINER_OBJECT).ws().append("=").ws()
|
||||
.append("Object.create(null);").newLine();
|
||||
}
|
||||
sourceWriter.append("var ").append(renderer.getNaming().getScopeName()).ws().append("=").ws()
|
||||
.append("Object.create(null);").newLine();
|
||||
if (!renderer.render(clsNodes)) {
|
||||
return;
|
||||
}
|
||||
@ -418,7 +418,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||
int totalSize = sourceWriter.getOffset() - start;
|
||||
printStats(renderer, totalSize);
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO Error occured", e);
|
||||
throw new RenderingException("IO Error occurred", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,15 +22,17 @@ import org.teavm.model.MethodReference;
|
||||
public interface AliasProvider {
|
||||
String getFieldAlias(FieldReference field);
|
||||
|
||||
String getStaticFieldAlias(FieldReference field);
|
||||
ScopedName getStaticFieldAlias(FieldReference field);
|
||||
|
||||
String getStaticMethodAlias(MethodReference method);
|
||||
ScopedName getStaticMethodAlias(MethodReference method);
|
||||
|
||||
String getMethodAlias(MethodDescriptor method);
|
||||
|
||||
String getClassAlias(String className);
|
||||
ScopedName getClassAlias(String className);
|
||||
|
||||
String getFunctionAlias(String name);
|
||||
|
||||
String getClassInitAlias(String className);
|
||||
ScopedName getClassInitAlias(String className);
|
||||
|
||||
String getScopeAlias();
|
||||
}
|
||||
|
@ -26,16 +26,22 @@ import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class DefaultAliasProvider implements AliasProvider {
|
||||
private final Map<String, String> classAliases = new HashMap<>();
|
||||
int topLevelAliasLimit;
|
||||
private final Map<String, ScopedName> classAliases = new HashMap<>();
|
||||
private final Set<String> knownAliases = new HashSet<>(200, 0.5f);
|
||||
private final ObjectIntMap<String> knowAliasesCounter = new ObjectIntHashMap<>();
|
||||
private final Set<String> knownScopedAliases = new HashSet<>(200, 0.5f);
|
||||
private final ObjectIntMap<String> knowScopedAliasesCounter = new ObjectIntHashMap<>();
|
||||
private final Set<String> knownVirtualAliases = new HashSet<>(200, 0.5f);
|
||||
private final ObjectIntMap<String> knowVirtualAliasesCounter = new ObjectIntHashMap<>();
|
||||
|
||||
public DefaultAliasProvider(int topLevelAliasLimit) {
|
||||
this.topLevelAliasLimit = topLevelAliasLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassAlias(String cls) {
|
||||
return classAliases.computeIfAbsent(cls, key -> makeUnique(knownAliases, knowAliasesCounter,
|
||||
suggestAliasForClass(key)));
|
||||
public ScopedName getClassAlias(String cls) {
|
||||
return classAliases.computeIfAbsent(cls, key -> makeUniqueTopLevel(suggestAliasForClass(key)));
|
||||
}
|
||||
|
||||
private static String suggestAliasForClass(String cls) {
|
||||
@ -89,18 +95,18 @@ public class DefaultAliasProvider implements AliasProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStaticMethodAlias(MethodReference method) {
|
||||
String alias = method.getDescriptor().getName();
|
||||
switch (alias) {
|
||||
public ScopedName getStaticMethodAlias(MethodReference method) {
|
||||
String suggested = method.getDescriptor().getName();
|
||||
switch (suggested) {
|
||||
case "<init>":
|
||||
alias = "_init_";
|
||||
suggested = "_init_";
|
||||
break;
|
||||
case "<clinit>":
|
||||
alias = "_clinit_";
|
||||
suggested = "_clinit_";
|
||||
break;
|
||||
}
|
||||
|
||||
return makeUnique(knownAliases, knowAliasesCounter, getClassAlias(method.getClassName()) + "_" + alias);
|
||||
return makeUniqueTopLevel(getClassAlias(method.getClassName()).value + "_" + suggested);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -109,9 +115,8 @@ public class DefaultAliasProvider implements AliasProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStaticFieldAlias(FieldReference field) {
|
||||
return makeUnique(knownAliases, knowAliasesCounter,
|
||||
getClassAlias(field.getClassName()) + "_" + field.getFieldName());
|
||||
public ScopedName getStaticFieldAlias(FieldReference field) {
|
||||
return makeUniqueTopLevel(getClassAlias(field.getClassName()).value + "_" + field.getFieldName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -120,8 +125,21 @@ public class DefaultAliasProvider implements AliasProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassInitAlias(String className) {
|
||||
return makeUnique(knownAliases, knowAliasesCounter, suggestAliasForClass(className) + "_$callClinit");
|
||||
public ScopedName getClassInitAlias(String className) {
|
||||
return makeUniqueTopLevel(suggestAliasForClass(className) + "_$callClinit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScopeAlias() {
|
||||
return makeUnique(knownAliases, knowAliasesCounter, "$java");
|
||||
}
|
||||
|
||||
private ScopedName makeUniqueTopLevel(String suggested) {
|
||||
if (knownAliases.size() < topLevelAliasLimit) {
|
||||
return new ScopedName(false, makeUnique(knownAliases, knowAliasesCounter, suggested));
|
||||
} else {
|
||||
return new ScopedName(true, makeUnique(knownScopedAliases, knowScopedAliasesCounter, suggested));
|
||||
}
|
||||
}
|
||||
|
||||
private String makeUnique(Set<String> knowAliases, ObjectIntMap<String> indexMap, String alias) {
|
||||
|
@ -23,12 +23,13 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||
private final AliasProvider aliasProvider;
|
||||
private final ClassReaderSource classSource;
|
||||
private final Map<String, String> aliases = new HashMap<>();
|
||||
private final Map<String, String> privateAliases = new HashMap<>();
|
||||
private final Map<String, String> classAliases = new HashMap<>();
|
||||
private final Map<String, ScopedName> privateAliases = new HashMap<>();
|
||||
private final Map<String, ScopedName> classAliases = new HashMap<>();
|
||||
private final Map<FieldReference, String> fieldAliases = new HashMap<>();
|
||||
private final Map<FieldReference, String> staticFieldAliases = new HashMap<>();
|
||||
private final Map<FieldReference, ScopedName> staticFieldAliases = new HashMap<>();
|
||||
private final Map<String, String> functionAliases = new HashMap<>();
|
||||
private final Map<String, String> classInitAliases = new HashMap<>();
|
||||
private final Map<String, ScopedName> classInitAliases = new HashMap<>();
|
||||
private String scopeName;
|
||||
|
||||
public DefaultNamingStrategy(AliasProvider aliasProvider, ClassReaderSource classSource) {
|
||||
this.aliasProvider = aliasProvider;
|
||||
@ -36,7 +37,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameFor(String cls) {
|
||||
public ScopedName getNameFor(String cls) {
|
||||
return classAliases.computeIfAbsent(cls, key -> aliasProvider.getClassAlias(cls));
|
||||
}
|
||||
|
||||
@ -52,16 +53,16 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullNameFor(MethodReference method) {
|
||||
public ScopedName getFullNameFor(MethodReference method) {
|
||||
return getFullNameFor(method, 'M');
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameForInit(MethodReference method) {
|
||||
public ScopedName getNameForInit(MethodReference method) {
|
||||
return getFullNameFor(method, 'I');
|
||||
}
|
||||
|
||||
private String getFullNameFor(MethodReference method, char classifier) {
|
||||
private ScopedName getFullNameFor(MethodReference method, char classifier) {
|
||||
MethodReference originalMethod = method;
|
||||
method = getRealMethod(method);
|
||||
if (method == null) {
|
||||
@ -89,14 +90,14 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullNameFor(FieldReference field) {
|
||||
String alias = staticFieldAliases.get(field);
|
||||
public ScopedName getFullNameFor(FieldReference field) {
|
||||
ScopedName alias = staticFieldAliases.get(field);
|
||||
if (alias == null) {
|
||||
FieldReference realField = getRealField(field);
|
||||
if (realField.equals(field)) {
|
||||
alias = aliasProvider.getStaticFieldAlias(realField);
|
||||
} else {
|
||||
alias = getNameFor(realField);
|
||||
alias = getFullNameFor(realField);
|
||||
}
|
||||
staticFieldAliases.put(field, alias);
|
||||
}
|
||||
@ -109,10 +110,18 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameForClassInit(String className) {
|
||||
public ScopedName getNameForClassInit(String className) {
|
||||
return classInitAliases.computeIfAbsent(className, key -> aliasProvider.getClassInitAlias(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScopeName() {
|
||||
if (scopeName == null) {
|
||||
scopeName = aliasProvider.getScopeAlias();
|
||||
}
|
||||
return scopeName;
|
||||
}
|
||||
|
||||
private MethodReference getRealMethod(MethodReference methodRef) {
|
||||
String className = methodRef.getClassName();
|
||||
while (className != null) {
|
||||
@ -133,7 +142,6 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||
}
|
||||
|
||||
private FieldReference getRealField(FieldReference fieldRef) {
|
||||
String initialCls = fieldRef.getClassName();
|
||||
String cls = fieldRef.getClassName();
|
||||
while (cls != null) {
|
||||
ClassReader clsReader = classSource.get(cls);
|
||||
|
@ -23,37 +23,37 @@ import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class MinifyingAliasProvider implements AliasProvider {
|
||||
private int topLevelAliasLimit;
|
||||
private static final String startLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
private static final String startVirtualLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
private int lastSuffix;
|
||||
private int lastScopedSuffix;
|
||||
private int lastVirtual;
|
||||
private final Set<String> usedAliases = new HashSet<>();
|
||||
private final Set<String> usedVirtualAliases = new HashSet<>();
|
||||
private final Set<String> usedScopedAliases = new HashSet<>();
|
||||
|
||||
public MinifyingAliasProvider(int topLevelAliasLimit) {
|
||||
this.topLevelAliasLimit = topLevelAliasLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldAlias(FieldReference field) {
|
||||
String result;
|
||||
do {
|
||||
result = RenderingUtil.indexToId(lastVirtual++, startVirtualLetters);
|
||||
} while (!usedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
} while (!usedVirtualAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStaticFieldAlias(FieldReference field) {
|
||||
String result;
|
||||
do {
|
||||
result = RenderingUtil.indexToId(lastSuffix++, startLetters);
|
||||
} while (!usedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
return result;
|
||||
public ScopedName getStaticFieldAlias(FieldReference field) {
|
||||
return createTopLevelName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStaticMethodAlias(MethodReference method) {
|
||||
String result;
|
||||
do {
|
||||
result = RenderingUtil.indexToId(lastSuffix++, startLetters);
|
||||
} while (!usedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
return result;
|
||||
public ScopedName getStaticMethodAlias(MethodReference method) {
|
||||
return createTopLevelName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -61,17 +61,13 @@ public class MinifyingAliasProvider implements AliasProvider {
|
||||
String result;
|
||||
do {
|
||||
result = RenderingUtil.indexToId(lastVirtual++, startVirtualLetters);
|
||||
} while (!usedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
} while (!usedVirtualAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassAlias(String className) {
|
||||
String result;
|
||||
do {
|
||||
result = RenderingUtil.indexToId(lastSuffix++, startLetters);
|
||||
} while (!usedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
return result;
|
||||
public ScopedName getClassAlias(String className) {
|
||||
return createTopLevelName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -80,11 +76,32 @@ public class MinifyingAliasProvider implements AliasProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassInitAlias(String className) {
|
||||
public ScopedName getClassInitAlias(String className) {
|
||||
return createTopLevelName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScopeAlias() {
|
||||
String result;
|
||||
do {
|
||||
result = RenderingUtil.indexToId(lastSuffix++, startLetters);
|
||||
} while (!usedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
private ScopedName createTopLevelName() {
|
||||
if (usedAliases.size() < topLevelAliasLimit) {
|
||||
String result;
|
||||
do {
|
||||
result = RenderingUtil.indexToId(lastSuffix++, startLetters);
|
||||
} while (!usedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
return new ScopedName(false, result);
|
||||
} else {
|
||||
String result;
|
||||
do {
|
||||
result = RenderingUtil.indexToId(lastScopedSuffix++, startLetters);
|
||||
} while (!usedScopedAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
||||
return new ScopedName(true, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,19 +20,21 @@ import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public interface NamingStrategy {
|
||||
String getNameFor(String cls);
|
||||
ScopedName getNameFor(String cls);
|
||||
|
||||
String getNameFor(MethodDescriptor method);
|
||||
|
||||
String getNameForInit(MethodReference method);
|
||||
ScopedName getNameForInit(MethodReference method);
|
||||
|
||||
String getFullNameFor(MethodReference method);
|
||||
ScopedName getFullNameFor(MethodReference method);
|
||||
|
||||
String getNameFor(FieldReference field);
|
||||
|
||||
String getFullNameFor(FieldReference method);
|
||||
ScopedName getFullNameFor(FieldReference method);
|
||||
|
||||
String getNameForFunction(String name);
|
||||
|
||||
String getNameForClassInit(String className);
|
||||
ScopedName getNameForClassInit(String className);
|
||||
|
||||
String getScopeName();
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2019 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.backend.javascript.codegen;
|
||||
|
||||
public class ScopedName {
|
||||
public final boolean scoped;
|
||||
public final String value;
|
||||
|
||||
public ScopedName(boolean scoped, String value) {
|
||||
this.scoped = scoped;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@
|
||||
package org.teavm.backend.javascript.codegen;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.backend.javascript.rendering.Renderer;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
@ -32,13 +31,11 @@ public class SourceWriter implements Appendable, LocationProvider {
|
||||
private int column;
|
||||
private int line;
|
||||
private int offset;
|
||||
private boolean classScoped;
|
||||
|
||||
SourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth, boolean classScoped) {
|
||||
SourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) {
|
||||
this.naming = naming;
|
||||
this.innerWriter = innerWriter;
|
||||
this.lineWidth = lineWidth;
|
||||
this.classScoped = classScoped;
|
||||
}
|
||||
|
||||
void setMinified(boolean minified) {
|
||||
@ -50,10 +47,6 @@ public class SourceWriter implements Appendable, LocationProvider {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SourceWriter append(Object value) throws IOException {
|
||||
return append(String.valueOf(value));
|
||||
}
|
||||
|
||||
public SourceWriter append(int value) throws IOException {
|
||||
return append(String.valueOf(value));
|
||||
}
|
||||
@ -102,8 +95,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
||||
}
|
||||
|
||||
public SourceWriter appendClass(String cls) throws IOException {
|
||||
appendScopeIfNecessary();
|
||||
return append(naming.getNameFor(cls));
|
||||
return appendName(naming.getNameFor(cls));
|
||||
}
|
||||
|
||||
public SourceWriter appendClass(Class<?> cls) throws IOException {
|
||||
@ -115,8 +107,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
||||
}
|
||||
|
||||
public SourceWriter appendStaticField(FieldReference field) throws IOException {
|
||||
appendScopeIfNecessary();
|
||||
return append(naming.getFullNameFor(field));
|
||||
return appendName(naming.getFullNameFor(field));
|
||||
}
|
||||
|
||||
public SourceWriter appendMethod(MethodDescriptor method) throws IOException {
|
||||
@ -128,8 +119,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
||||
}
|
||||
|
||||
public SourceWriter appendMethodBody(MethodReference method) throws IOException {
|
||||
appendScopeIfNecessary();
|
||||
return append(naming.getFullNameFor(method));
|
||||
return appendName(naming.getFullNameFor(method));
|
||||
}
|
||||
|
||||
public SourceWriter appendMethodBody(String className, String name, ValueType... params) throws IOException {
|
||||
@ -145,19 +135,19 @@ public class SourceWriter implements Appendable, LocationProvider {
|
||||
}
|
||||
|
||||
public SourceWriter appendInit(MethodReference method) throws IOException {
|
||||
appendScopeIfNecessary();
|
||||
return append(naming.getNameForInit(method));
|
||||
return appendName(naming.getNameForInit(method));
|
||||
}
|
||||
|
||||
public SourceWriter appendClassInit(String className) throws IOException {
|
||||
appendScopeIfNecessary();
|
||||
return append(naming.getNameForClassInit(className));
|
||||
return appendName(naming.getNameForClassInit(className));
|
||||
}
|
||||
|
||||
private void appendScopeIfNecessary() throws IOException {
|
||||
if (classScoped) {
|
||||
append(Renderer.CONTAINER_OBJECT).append(".");
|
||||
private SourceWriter appendName(ScopedName name) throws IOException {
|
||||
if (name.scoped) {
|
||||
append(naming.getScopeName()).append(".");
|
||||
}
|
||||
append(name.value);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void appendIndent() throws IOException {
|
||||
|
@ -18,7 +18,6 @@ package org.teavm.backend.javascript.codegen;
|
||||
public class SourceWriterBuilder {
|
||||
private NamingStrategy naming;
|
||||
private boolean minified;
|
||||
private boolean classScoped;
|
||||
private int lineWidth = 512;
|
||||
|
||||
public SourceWriterBuilder(NamingStrategy naming) {
|
||||
@ -37,12 +36,8 @@ public class SourceWriterBuilder {
|
||||
this.lineWidth = lineWidth;
|
||||
}
|
||||
|
||||
public void setClassScoped(boolean classScoped) {
|
||||
this.classScoped = classScoped;
|
||||
}
|
||||
|
||||
public SourceWriter build(Appendable innerWriter) {
|
||||
SourceWriter writer = new SourceWriter(naming, innerWriter, lineWidth, classScoped);
|
||||
SourceWriter writer = new SourceWriter(naming, innerWriter, lineWidth);
|
||||
writer.setMinified(minified);
|
||||
return writer;
|
||||
}
|
||||
|
@ -700,7 +700,7 @@ public class AstWriter {
|
||||
writer.append("let").ws().append('(');
|
||||
printList(node.getVariables().getVariables());
|
||||
writer.append(')');
|
||||
writer.append(node.getBody());
|
||||
print(node.getBody());
|
||||
}
|
||||
|
||||
private void print(ParenthesizedExpression node, int precedence) throws IOException {
|
||||
|
@ -40,6 +40,7 @@ import org.teavm.ast.RegularMethodNode;
|
||||
import org.teavm.ast.VariableNode;
|
||||
import org.teavm.backend.javascript.codegen.NamingOrderer;
|
||||
import org.teavm.backend.javascript.codegen.NamingStrategy;
|
||||
import org.teavm.backend.javascript.codegen.ScopedName;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||
import org.teavm.backend.javascript.spi.GeneratorContext;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
@ -61,13 +62,11 @@ import org.teavm.vm.RenderingException;
|
||||
import org.teavm.vm.TeaVMProgressFeedback;
|
||||
|
||||
public class Renderer implements RenderingManager {
|
||||
public static final String CONTAINER_OBJECT = "$java";
|
||||
private final NamingStrategy naming;
|
||||
private final SourceWriter writer;
|
||||
private final ListableClassReaderSource classSource;
|
||||
private final ClassLoader classLoader;
|
||||
private boolean minifying;
|
||||
private boolean classScoped;
|
||||
private final Properties properties = new Properties();
|
||||
private final ServiceRepository services;
|
||||
private DebugInformationEmitter debugEmitter = new DummyDebugInformationEmitter();
|
||||
@ -86,7 +85,7 @@ public class Renderer implements RenderingManager {
|
||||
private boolean threadLibraryUsed;
|
||||
|
||||
public Renderer(SourceWriter writer, Set<MethodReference> asyncMethods, Set<MethodReference> asyncFamilyMethods,
|
||||
Diagnostics diagnostics, RenderingContext context, boolean classScoped) {
|
||||
Diagnostics diagnostics, RenderingContext context) {
|
||||
this.naming = context.getNaming();
|
||||
this.writer = writer;
|
||||
this.classSource = context.getClassSource();
|
||||
@ -96,7 +95,6 @@ public class Renderer implements RenderingManager {
|
||||
this.asyncFamilyMethods = new HashSet<>(asyncFamilyMethods);
|
||||
this.diagnostics = diagnostics;
|
||||
this.context = context;
|
||||
this.classScoped = classScoped;
|
||||
}
|
||||
|
||||
public boolean isLongLibraryUsed() {
|
||||
@ -272,6 +270,7 @@ public class Renderer implements RenderingManager {
|
||||
for (ClassNode cls : classes) {
|
||||
estimator.estimate(cls);
|
||||
}
|
||||
naming.getScopeName();
|
||||
orderer.apply(naming);
|
||||
}
|
||||
}
|
||||
@ -299,8 +298,8 @@ public class Renderer implements RenderingManager {
|
||||
}
|
||||
|
||||
private void renderDeclaration(ClassNode cls) throws RenderingException {
|
||||
String jsName = naming.getNameFor(cls.getName());
|
||||
debugEmitter.addClass(jsName, cls.getName(), cls.getParentName());
|
||||
ScopedName jsName = naming.getNameFor(cls.getName());
|
||||
debugEmitter.addClass(jsName.value, cls.getName(), cls.getParentName());
|
||||
try {
|
||||
renderFunctionDeclaration(jsName);
|
||||
writer.append("()").ws().append("{")
|
||||
@ -341,7 +340,7 @@ public class Renderer implements RenderingManager {
|
||||
}
|
||||
|
||||
writer.outdent().append("}");
|
||||
if (classScoped) {
|
||||
if (jsName.scoped) {
|
||||
writer.append(";");
|
||||
}
|
||||
writer.newLine();
|
||||
@ -357,12 +356,14 @@ public class Renderer implements RenderingManager {
|
||||
postponedFieldInitializers.add(new PostponedFieldInitializer(fieldRef, (String) value));
|
||||
value = null;
|
||||
}
|
||||
if (classScoped) {
|
||||
writer.append(CONTAINER_OBJECT).append(".");
|
||||
|
||||
ScopedName fieldName = naming.getFullNameFor(fieldRef);
|
||||
if (fieldName.scoped) {
|
||||
writer.append(naming.getScopeName()).append(".");
|
||||
} else {
|
||||
writer.append("var ");
|
||||
}
|
||||
writer.append(naming.getFullNameFor(fieldRef)).ws().append("=").ws();
|
||||
writer.append(fieldName.value).ws().append("=").ws();
|
||||
context.constantToString(writer, value);
|
||||
writer.append(";").softNewLine();
|
||||
}
|
||||
@ -403,12 +404,15 @@ public class Renderer implements RenderingManager {
|
||||
throws IOException {
|
||||
boolean isAsync = asyncMethods.contains(clinit.getReference());
|
||||
|
||||
String clinitCalled = naming.getNameFor(cls.getName()) + "_$clinitCalled";
|
||||
ScopedName className = naming.getNameFor(cls.getName());
|
||||
String clinitCalled = (className.scoped ? naming.getScopeName() + "_" : "") + className.value
|
||||
+ "_$clinitCalled";
|
||||
if (isAsync) {
|
||||
writer.append("var ").append(clinitCalled).ws().append("=").ws().append("false;").softNewLine();
|
||||
}
|
||||
|
||||
renderFunctionDeclaration(naming.getNameForClassInit(cls.getName()));
|
||||
ScopedName name = naming.getNameForClassInit(cls.getName());
|
||||
renderFunctionDeclaration(name);
|
||||
writer.append("()").ws()
|
||||
.append("{").softNewLine().indent();
|
||||
|
||||
@ -454,7 +458,7 @@ public class Renderer implements RenderingManager {
|
||||
}
|
||||
|
||||
writer.outdent().append("}");
|
||||
if (classScoped) {
|
||||
if (name.scoped) {
|
||||
writer.append(";");
|
||||
}
|
||||
writer.newLine();
|
||||
@ -703,7 +707,8 @@ public class Renderer implements RenderingManager {
|
||||
private void renderInitializer(MethodNode method) throws IOException {
|
||||
MethodReference ref = method.getReference();
|
||||
debugEmitter.emitMethod(ref.getDescriptor());
|
||||
renderFunctionDeclaration(naming.getNameForInit(ref));
|
||||
ScopedName name = naming.getNameForInit(ref);
|
||||
renderFunctionDeclaration(name);
|
||||
writer.append("(");
|
||||
for (int i = 0; i < ref.parameterCount(); ++i) {
|
||||
if (i > 0) {
|
||||
@ -724,7 +729,7 @@ public class Renderer implements RenderingManager {
|
||||
writer.append(");").softNewLine();
|
||||
writer.append("return " + instanceName + ";").softNewLine();
|
||||
writer.outdent().append("}");
|
||||
if (classScoped) {
|
||||
if (name.scoped) {
|
||||
writer.append(";");
|
||||
}
|
||||
writer.newLine();
|
||||
@ -790,7 +795,7 @@ public class Renderer implements RenderingManager {
|
||||
|
||||
MethodReference ref = method.getReference();
|
||||
debugEmitter.emitMethod(ref.getDescriptor());
|
||||
String name = naming.getFullNameFor(ref);
|
||||
ScopedName name = naming.getFullNameFor(ref);
|
||||
|
||||
renderFunctionDeclaration(name);
|
||||
writer.append("(");
|
||||
@ -808,7 +813,7 @@ public class Renderer implements RenderingManager {
|
||||
|
||||
method.acceptVisitor(new MethodBodyRenderer(statementRenderer));
|
||||
writer.outdent().append("}");
|
||||
if (classScoped) {
|
||||
if (name.scoped) {
|
||||
writer.append(";");
|
||||
}
|
||||
|
||||
@ -818,13 +823,13 @@ public class Renderer implements RenderingManager {
|
||||
longLibraryUsed |= statementRenderer.isLongLibraryUsed();
|
||||
}
|
||||
|
||||
private void renderFunctionDeclaration(String name) throws IOException {
|
||||
if (classScoped) {
|
||||
writer.append(CONTAINER_OBJECT).append(".").append(name).ws().append("=").ws();
|
||||
private void renderFunctionDeclaration(ScopedName name) throws IOException {
|
||||
if (name.scoped) {
|
||||
writer.append(naming.getScopeName()).append(".").append(name.value).ws().append("=").ws();
|
||||
}
|
||||
writer.append("function");
|
||||
if (!classScoped) {
|
||||
writer.append(" ").append(name);
|
||||
if (!name.scoped) {
|
||||
writer.append(" ").append(name.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ import java.nio.charset.StandardCharsets;
|
||||
import org.mozilla.javascript.CompilerEnvirons;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.ast.AstRoot;
|
||||
import org.teavm.backend.javascript.codegen.NamingStrategy;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
@ -48,12 +47,10 @@ public class RuntimeRenderer {
|
||||
"setStackTrace", StackTraceElement[].class, void.class);
|
||||
|
||||
private final ClassReaderSource classSource;
|
||||
private final NamingStrategy naming;
|
||||
private final SourceWriter writer;
|
||||
|
||||
public RuntimeRenderer(ClassReaderSource classSource, NamingStrategy naming, SourceWriter writer) {
|
||||
public RuntimeRenderer(ClassReaderSource classSource, SourceWriter writer) {
|
||||
this.classSource = classSource;
|
||||
this.naming = naming;
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
|
@ -68,13 +68,16 @@ public class Inlining {
|
||||
private InliningStrategy strategy;
|
||||
private MethodUsageCounter usageCounter;
|
||||
private Set<MethodReference> methodsUsedOnce = new HashSet<>();
|
||||
private boolean devirtualization;
|
||||
|
||||
public Inlining(ClassHierarchy hierarchy, DependencyInfo dependencyInfo, InliningStrategy strategy,
|
||||
ListableClassReaderSource classes, Predicate<MethodReference> externalMethods) {
|
||||
ListableClassReaderSource classes, Predicate<MethodReference> externalMethods,
|
||||
boolean devirtualization) {
|
||||
this.hierarchy = hierarchy;
|
||||
this.classes = classes;
|
||||
this.dependencyInfo = dependencyInfo;
|
||||
this.strategy = strategy;
|
||||
this.devirtualization = devirtualization;
|
||||
usageCounter = new MethodUsageCounter(externalMethods);
|
||||
|
||||
for (String className : classes.getClassNames()) {
|
||||
@ -156,8 +159,12 @@ public class Inlining {
|
||||
}
|
||||
instructionsToSkip = new HashSet<>();
|
||||
|
||||
while (applyOnce(program, method)) {
|
||||
devirtualize(program, method, dependencyInfo);
|
||||
if (devirtualization) {
|
||||
while (applyOnce(program, method)) {
|
||||
devirtualize(program, method, dependencyInfo);
|
||||
}
|
||||
} else {
|
||||
applyOnce(program, method);
|
||||
}
|
||||
depthsByBlock = null;
|
||||
instructionsToSkip = null;
|
||||
|
@ -550,7 +550,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||
}
|
||||
|
||||
Inlining inlining = new Inlining(new ClassHierarchy(classes), dependencyAnalyzer, inliningStrategy,
|
||||
classes, this::isExternal);
|
||||
classes, this::isExternal, optimizationLevel == TeaVMOptimizationLevel.FULL);
|
||||
List<MethodReference> methodReferences = inlining.getOrder();
|
||||
int classCount = classes.getClassNames().size();
|
||||
int initialValue = compileProgressValue;
|
||||
|
@ -30,7 +30,7 @@ final class ResourceWriterHelper {
|
||||
if (resource instanceof ResourceWriter) {
|
||||
((ResourceWriter) resource).write(writer);
|
||||
} else if (resource instanceof Number) {
|
||||
writer.append(resource);
|
||||
writer.append(resource.toString());
|
||||
} else if (resource instanceof Boolean) {
|
||||
writer.append(resource == Boolean.TRUE ? "true" : "false");
|
||||
} else if (resource instanceof String) {
|
||||
|
@ -134,6 +134,13 @@ public final class TeaVMRunner {
|
||||
.hasArg()
|
||||
.withDescription("Minimum heap size in bytes (for C and WebAssembly)")
|
||||
.create());
|
||||
options.addOption(OptionBuilder
|
||||
.withLongOpt("max-toplevel-names")
|
||||
.withArgName("number")
|
||||
.hasArg()
|
||||
.withDescription("Maximum number of names kept in top-level scope ("
|
||||
+ "other will be put in a separate object. 10000 by default.")
|
||||
.create());
|
||||
}
|
||||
|
||||
private TeaVMRunner(CommandLine commandLine) {
|
||||
@ -215,10 +222,15 @@ public final class TeaVMRunner {
|
||||
}
|
||||
|
||||
private void parseJavaScriptOptions() {
|
||||
if (commandLine.hasOption("m")) {
|
||||
tool.setMinifying(true);
|
||||
} else {
|
||||
tool.setMinifying(false);
|
||||
tool.setMinifying(commandLine.hasOption("m"));
|
||||
|
||||
if (commandLine.hasOption("max-toplevel-names")) {
|
||||
try {
|
||||
tool.setMaxTopLevelNames(Integer.parseInt(commandLine.getOptionValue("max-toplevel-names")));
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("'--max-toplevel-names' must be integer number");
|
||||
printUsage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ public class TeaVMTool {
|
||||
private TeaVMTargetType targetType = TeaVMTargetType.JAVASCRIPT;
|
||||
private String targetFileName = "";
|
||||
private boolean minifying = true;
|
||||
private int maxTopLevelNames = 10000;
|
||||
private String mainClass;
|
||||
private String entryPointName = "main";
|
||||
private Properties properties = new Properties();
|
||||
@ -124,6 +125,10 @@ public class TeaVMTool {
|
||||
this.minifying = minifying;
|
||||
}
|
||||
|
||||
public void setMaxTopLevelNames(int maxTopLevelNames) {
|
||||
this.maxTopLevelNames = maxTopLevelNames;
|
||||
}
|
||||
|
||||
public boolean isIncremental() {
|
||||
return incremental;
|
||||
}
|
||||
@ -291,6 +296,7 @@ public class TeaVMTool {
|
||||
private TeaVMTarget prepareJavaScriptTarget() {
|
||||
javaScriptTarget = new JavaScriptTarget();
|
||||
javaScriptTarget.setMinifying(minifying);
|
||||
javaScriptTarget.setTopLevelNameLimit(maxTopLevelNames);
|
||||
|
||||
debugEmitter = debugInformationGenerated || sourceMapsFileGenerated
|
||||
? new DebugInformationBuilder() : null;
|
||||
|
@ -54,6 +54,8 @@ public interface BuildStrategy {
|
||||
|
||||
void setMinifying(boolean minifying);
|
||||
|
||||
void setMaxTopLevelNames(int maxTopLevelNames);
|
||||
|
||||
void setProperties(Properties properties);
|
||||
|
||||
void setTransformers(String[] transformers);
|
||||
|
@ -52,6 +52,7 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
||||
private TeaVMOptimizationLevel optimizationLevel = TeaVMOptimizationLevel.ADVANCED;
|
||||
private boolean fastDependencyAnalysis;
|
||||
private boolean minifying;
|
||||
private int maxTopLevelNames;
|
||||
private boolean sourceMapsFileGenerated;
|
||||
private boolean debugInformationGenerated;
|
||||
private boolean sourceFilesCopied;
|
||||
@ -150,6 +151,11 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
||||
this.minifying = minifying;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxTopLevelNames(int maxTopLevelNames) {
|
||||
this.maxTopLevelNames = maxTopLevelNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransformers(String[] transformers) {
|
||||
this.transformers = transformers.clone();
|
||||
@ -209,6 +215,7 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
||||
tool.setSourceFilesCopied(sourceFilesCopied);
|
||||
|
||||
tool.setMinifying(minifying);
|
||||
tool.setMaxTopLevelNames(maxTopLevelNames);
|
||||
tool.setIncremental(incremental);
|
||||
tool.getTransformers().addAll(Arrays.asList(transformers));
|
||||
tool.getClassesToPreserve().addAll(Arrays.asList(classesToPreserve));
|
||||
|
@ -129,6 +129,11 @@ public class RemoteBuildStrategy implements BuildStrategy {
|
||||
request.minifying = minifying;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxTopLevelNames(int maxTopLevelNames) {
|
||||
request.maxTopLevelNames = maxTopLevelNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransformers(String[] transformers) {
|
||||
request.transformers = transformers.clone();
|
||||
|
@ -156,6 +156,7 @@ public class BuildDaemon extends UnicastRemoteObject implements RemoteBuildServi
|
||||
tool.setOptimizationLevel(request.optimizationLevel);
|
||||
tool.setFastDependencyAnalysis(request.fastDependencyAnalysis);
|
||||
tool.setMinifying(request.minifying);
|
||||
tool.setMaxTopLevelNames(request.maxTopLevelNames);
|
||||
tool.setWasmVersion(request.wasmVersion);
|
||||
tool.setMinHeapSize(request.heapSize);
|
||||
|
||||
|
@ -40,6 +40,7 @@ public class RemoteBuildRequest implements Serializable {
|
||||
public boolean incremental;
|
||||
public String cacheDirectory;
|
||||
public boolean minifying;
|
||||
public int maxTopLevelNames;
|
||||
public Properties properties;
|
||||
public TeaVMOptimizationLevel optimizationLevel;
|
||||
public boolean fastDependencyAnalysis;
|
||||
|
@ -745,7 +745,7 @@ public class CodeServlet extends HttpServlet {
|
||||
jsTarget.setMinifying(false);
|
||||
jsTarget.setAstCache(astCache);
|
||||
jsTarget.setDebugEmitter(debugInformationBuilder);
|
||||
jsTarget.setClassScoped(true);
|
||||
jsTarget.setTopLevelNameLimit(500);
|
||||
vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
|
||||
vm.setCacheStatus(classSource);
|
||||
vm.addVirtualMethods(m -> true);
|
||||
|
@ -80,6 +80,9 @@ public class TeaVMCompileMojo extends AbstractMojo {
|
||||
@Parameter(property = "teavm.minifying", defaultValue = "true")
|
||||
private boolean minifying = true;
|
||||
|
||||
@Parameter(property = "teavm.maxTopLevelNames", defaultValue = "10000")
|
||||
private int maxTopLevelNames = 10000;
|
||||
|
||||
@Parameter
|
||||
private Properties properties;
|
||||
|
||||
@ -148,6 +151,7 @@ public class TeaVMCompileMojo extends AbstractMojo {
|
||||
try {
|
||||
builder.setClassPathEntries(prepareClassPath());
|
||||
builder.setMinifying(minifying);
|
||||
builder.setMaxTopLevelNames(maxTopLevelNames);
|
||||
builder.setTargetDirectory(targetDirectory.getAbsolutePath());
|
||||
if (transformers != null) {
|
||||
builder.setTransformers(transformers);
|
||||
|
Loading…
Reference in New Issue
Block a user