mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
js: add limit for top-level declarations
Rationale: turns out that V8 utilizes stack even to represent module-level functions. This can cause SOE when there's too many classes and methods in source JVM
This commit is contained in:
parent
ca273390ef
commit
6ac598b927
|
@ -44,7 +44,7 @@ public class ServiceLoaderJSSupport implements Generator {
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
writer.append("[").appendClass(implName).append(",").ws()
|
writer.append("[").appendClass(implName).append(",").ws()
|
||||||
.appendMethodBody(new MethodReference(implName, INIT_METHOD))
|
.appendMethod(new MethodReference(implName, INIT_METHOD))
|
||||||
.append("]");
|
.append("]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,7 +272,7 @@ public class ClassGenerator implements Generator, Injector, DependencyPlugin {
|
||||||
if (method.getResultType() != ValueType.VOID) {
|
if (method.getResultType() != ValueType.VOID) {
|
||||||
writer.append("return ");
|
writer.append("return ");
|
||||||
}
|
}
|
||||||
writer.appendMethodBody(method.getReference());
|
writer.appendMethod(method.getReference());
|
||||||
|
|
||||||
writer.append('(');
|
writer.append('(');
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
|
@ -315,30 +315,30 @@ public class ClassGenerator implements Generator, Injector, DependencyPlugin {
|
||||||
if (type instanceof ValueType.Primitive) {
|
if (type instanceof ValueType.Primitive) {
|
||||||
switch (((ValueType.Primitive) type).getKind()) {
|
switch (((ValueType.Primitive) type).getKind()) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
writer.appendMethodBody(new MethodReference(Boolean.class, "valueOf", boolean.class,
|
writer.appendMethod(new MethodReference(Boolean.class, "valueOf", boolean.class,
|
||||||
Boolean.class));
|
Boolean.class));
|
||||||
break;
|
break;
|
||||||
case BYTE:
|
case BYTE:
|
||||||
writer.appendMethodBody(new MethodReference(Byte.class, "valueOf", byte.class, Byte.class));
|
writer.appendMethod(new MethodReference(Byte.class, "valueOf", byte.class, Byte.class));
|
||||||
break;
|
break;
|
||||||
case SHORT:
|
case SHORT:
|
||||||
writer.appendMethodBody(new MethodReference(Short.class, "valueOf", short.class, Short.class));
|
writer.appendMethod(new MethodReference(Short.class, "valueOf", short.class, Short.class));
|
||||||
break;
|
break;
|
||||||
case CHARACTER:
|
case CHARACTER:
|
||||||
writer.appendMethodBody(new MethodReference(Character.class, "valueOf", char.class,
|
writer.appendMethod(new MethodReference(Character.class, "valueOf", char.class,
|
||||||
Character.class));
|
Character.class));
|
||||||
break;
|
break;
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
writer.appendMethodBody(new MethodReference(Integer.class, "valueOf", int.class, Integer.class));
|
writer.appendMethod(new MethodReference(Integer.class, "valueOf", int.class, Integer.class));
|
||||||
break;
|
break;
|
||||||
case LONG:
|
case LONG:
|
||||||
writer.appendMethodBody(new MethodReference(Long.class, "valueOf", long.class, Long.class));
|
writer.appendMethod(new MethodReference(Long.class, "valueOf", long.class, Long.class));
|
||||||
break;
|
break;
|
||||||
case FLOAT:
|
case FLOAT:
|
||||||
writer.appendMethodBody(new MethodReference(Float.class, "valueOf", float.class, Float.class));
|
writer.appendMethod(new MethodReference(Float.class, "valueOf", float.class, Float.class));
|
||||||
break;
|
break;
|
||||||
case DOUBLE:
|
case DOUBLE:
|
||||||
writer.appendMethodBody(new MethodReference(Double.class, "valueOf", double.class, Double.class));
|
writer.appendMethod(new MethodReference(Double.class, "valueOf", double.class, Double.class));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
writer.append('(');
|
writer.append('(');
|
||||||
|
@ -355,28 +355,28 @@ public class ClassGenerator implements Generator, Injector, DependencyPlugin {
|
||||||
if (type instanceof ValueType.Primitive) {
|
if (type instanceof ValueType.Primitive) {
|
||||||
switch (((ValueType.Primitive) type).getKind()) {
|
switch (((ValueType.Primitive) type).getKind()) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
writer.appendMethodBody(new MethodReference(Boolean.class, "booleanValue", boolean.class));
|
writer.appendMethod(new MethodReference(Boolean.class, "booleanValue", boolean.class));
|
||||||
break;
|
break;
|
||||||
case BYTE:
|
case BYTE:
|
||||||
writer.appendMethodBody(new MethodReference(Byte.class, "byteValue", byte.class));
|
writer.appendMethod(new MethodReference(Byte.class, "byteValue", byte.class));
|
||||||
break;
|
break;
|
||||||
case SHORT:
|
case SHORT:
|
||||||
writer.appendMethodBody(new MethodReference(Short.class, "shortValue", short.class));
|
writer.appendMethod(new MethodReference(Short.class, "shortValue", short.class));
|
||||||
break;
|
break;
|
||||||
case CHARACTER:
|
case CHARACTER:
|
||||||
writer.appendMethodBody(new MethodReference(Character.class, "charValue", char.class));
|
writer.appendMethod(new MethodReference(Character.class, "charValue", char.class));
|
||||||
break;
|
break;
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
writer.appendMethodBody(new MethodReference(Integer.class, "intValue", int.class));
|
writer.appendMethod(new MethodReference(Integer.class, "intValue", int.class));
|
||||||
break;
|
break;
|
||||||
case LONG:
|
case LONG:
|
||||||
writer.appendMethodBody(new MethodReference(Long.class, "longValue", long.class));
|
writer.appendMethod(new MethodReference(Long.class, "longValue", long.class));
|
||||||
break;
|
break;
|
||||||
case FLOAT:
|
case FLOAT:
|
||||||
writer.appendMethodBody(new MethodReference(Float.class, "floatValue", float.class));
|
writer.appendMethod(new MethodReference(Float.class, "floatValue", float.class));
|
||||||
break;
|
break;
|
||||||
case DOUBLE:
|
case DOUBLE:
|
||||||
writer.appendMethodBody(new MethodReference(Double.class, "doubleValue", double.class));
|
writer.appendMethod(new MethodReference(Double.class, "doubleValue", double.class));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
writer.append('(');
|
writer.append('(');
|
||||||
|
|
|
@ -129,6 +129,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
private final Map<String, String> importedModules = new LinkedHashMap<>();
|
private final Map<String, String> importedModules = new LinkedHashMap<>();
|
||||||
private JavaScriptTemplateFactory templateFactory;
|
private JavaScriptTemplateFactory templateFactory;
|
||||||
private JSModuleType moduleType = JSModuleType.UMD;
|
private JSModuleType moduleType = JSModuleType.UMD;
|
||||||
|
private int maxTopLevelNames = 80_000;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ClassHolderTransformer> getTransformers() {
|
public List<ClassHolderTransformer> getTransformers() {
|
||||||
|
@ -228,6 +229,10 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
this.stackTraceIncluded = stackTraceIncluded;
|
this.stackTraceIncluded = stackTraceIncluded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxTopLevelNames(int maxTopLevelNames) {
|
||||||
|
this.maxTopLevelNames = maxTopLevelNames;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TeaVMHostExtension> getHostExtensions() {
|
public List<TeaVMHostExtension> getHostExtensions() {
|
||||||
return Collections.singletonList(this);
|
return Collections.singletonList(this);
|
||||||
|
@ -351,7 +356,9 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void emit(ListableClassHolderSource classes, Writer writer, BuildTarget target) {
|
private void emit(ListableClassHolderSource classes, Writer writer, BuildTarget target) {
|
||||||
var aliasProvider = obfuscated ? new MinifyingAliasProvider() : new DefaultAliasProvider();
|
var aliasProvider = obfuscated
|
||||||
|
? new MinifyingAliasProvider(maxTopLevelNames)
|
||||||
|
: new DefaultAliasProvider(maxTopLevelNames);
|
||||||
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, controller.getUnprocessedClassSource());
|
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, controller.getUnprocessedClassSource());
|
||||||
DebugInformationEmitter debugEmitterToUse = debugEmitter;
|
DebugInformationEmitter debugEmitterToUse = debugEmitter;
|
||||||
if (debugEmitterToUse == null) {
|
if (debugEmitterToUse == null) {
|
||||||
|
@ -410,9 +417,9 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
for (var entry : controller.getEntryPoints().entrySet()) {
|
for (var entry : controller.getEntryPoints().entrySet()) {
|
||||||
var alias = "$rt_export_" + entry.getKey();
|
var alias = "$rt_export_" + entry.getKey();
|
||||||
var ref = entry.getValue().getMethod();
|
var ref = entry.getValue().getMethod();
|
||||||
rememberingWriter.append("let ").appendFunction(alias).ws().append("=").ws()
|
rememberingWriter.startVariableDeclaration().appendFunction(alias)
|
||||||
.appendFunction("$rt_mainStarter").append("(").appendMethodBody(ref);
|
.appendFunction("$rt_mainStarter").append("(").appendMethod(ref);
|
||||||
rememberingWriter.append(");").newLine();
|
rememberingWriter.append(")").endDeclaration();
|
||||||
rememberingWriter.appendFunction(alias).append(".")
|
rememberingWriter.appendFunction(alias).append(".")
|
||||||
.append("javaException").ws().append("=").ws().appendFunction("$rt_javaException")
|
.append("javaException").ws().append("=").ws().appendFunction("$rt_javaException")
|
||||||
.append(";").newLine();
|
.append(";").newLine();
|
||||||
|
@ -424,31 +431,49 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
var epilogue = rememberingWriter.save();
|
var epilogue = rememberingWriter.save();
|
||||||
rememberingWriter.clear();
|
rememberingWriter.clear();
|
||||||
|
|
||||||
if (renderingContext.isMinifying()) {
|
var runtimeRenderer = new RuntimeRenderer(classes, rememberingWriter, controller.getClassInitializerInfo());
|
||||||
var frequencyEstimator = new NameFrequencyEstimator();
|
|
||||||
declarations.replay(frequencyEstimator, RememberedSource.FILTER_REF);
|
|
||||||
epilogue.replay(frequencyEstimator, RememberedSource.FILTER_REF);
|
|
||||||
frequencyEstimator.apply(naming);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sourceWriter = builder.build(writer);
|
|
||||||
sourceWriter.setDebugInformationEmitter(debugEmitterToUse);
|
|
||||||
printWrapperStart(sourceWriter);
|
|
||||||
|
|
||||||
int start = sourceWriter.getOffset();
|
|
||||||
|
|
||||||
RuntimeRenderer runtimeRenderer = new RuntimeRenderer(classes, sourceWriter,
|
|
||||||
controller.getClassInitializerInfo());
|
|
||||||
runtimeRenderer.prepareAstParts(renderer.isThreadLibraryUsed());
|
runtimeRenderer.prepareAstParts(renderer.isThreadLibraryUsed());
|
||||||
declarations.replay(runtimeRenderer.sink, RememberedSource.FILTER_REF);
|
declarations.replay(runtimeRenderer.sink, RememberedSource.FILTER_REF);
|
||||||
epilogue.replay(runtimeRenderer.sink, RememberedSource.FILTER_REF);
|
epilogue.replay(runtimeRenderer.sink, RememberedSource.FILTER_REF);
|
||||||
runtimeRenderer.removeUnusedParts();
|
runtimeRenderer.removeUnusedParts();
|
||||||
runtimeRenderer.renderRuntime();
|
runtimeRenderer.renderRuntime();
|
||||||
declarations.write(sourceWriter, 0);
|
var runtime = rememberingWriter.save();
|
||||||
|
rememberingWriter.clear();
|
||||||
runtimeRenderer.renderEpilogue();
|
runtimeRenderer.renderEpilogue();
|
||||||
|
var runtimeEpilogue = rememberingWriter.save();
|
||||||
|
rememberingWriter.clear();
|
||||||
|
|
||||||
|
naming.additionalScopeName();
|
||||||
|
naming.functionName("$rt_exports");
|
||||||
|
for (var module : importedModules.values()) {
|
||||||
|
naming.functionName(module);
|
||||||
|
}
|
||||||
|
for (var exportedName : controller.getEntryPoints().keySet()) {
|
||||||
|
naming.functionName("$rt_export_" + exportedName);
|
||||||
|
}
|
||||||
|
var frequencyEstimator = new NameFrequencyEstimator();
|
||||||
|
runtime.replay(frequencyEstimator, RememberedSource.FILTER_REF);
|
||||||
|
runtimeEpilogue.replay(frequencyEstimator, RememberedSource.FILTER_REF);
|
||||||
|
declarations.replay(frequencyEstimator, RememberedSource.FILTER_REF);
|
||||||
|
epilogue.replay(frequencyEstimator, RememberedSource.FILTER_REF);
|
||||||
|
frequencyEstimator.apply(naming);
|
||||||
|
|
||||||
|
var sourceWriter = builder.build(writer);
|
||||||
|
sourceWriter.setDebugInformationEmitter(debugEmitterToUse);
|
||||||
|
printWrapperStart(sourceWriter);
|
||||||
|
if (frequencyEstimator.hasAdditionalScope()) {
|
||||||
|
sourceWriter.append("let ").append(naming.additionalScopeName()).ws().append('=').ws()
|
||||||
|
.append("{};").softNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
int start = sourceWriter.getOffset();
|
||||||
|
runtime.write(sourceWriter, 0);
|
||||||
|
declarations.write(sourceWriter, 0);
|
||||||
|
runtimeEpilogue.write(sourceWriter, 0);
|
||||||
epilogue.write(sourceWriter, 0);
|
epilogue.write(sourceWriter, 0);
|
||||||
|
|
||||||
printWrapperEnd(sourceWriter);
|
printModuleEnd(sourceWriter);
|
||||||
|
sourceWriter.finish();
|
||||||
|
|
||||||
int totalSize = sourceWriter.getOffset() - start;
|
int totalSize = sourceWriter.getOffset() - start;
|
||||||
printStats(sourceWriter, totalSize);
|
printStats(sourceWriter, totalSize);
|
||||||
|
@ -560,7 +585,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printWrapperEnd(SourceWriter writer) {
|
private void printModuleEnd(SourceWriter writer) {
|
||||||
switch (moduleType) {
|
switch (moduleType) {
|
||||||
case UMD:
|
case UMD:
|
||||||
printUmdEnd(writer);
|
printUmdEnd(writer);
|
||||||
|
@ -580,7 +605,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
private void printUmdEnd(SourceWriter writer) {
|
private void printUmdEnd(SourceWriter writer) {
|
||||||
for (var export : controller.getEntryPoints().keySet()) {
|
for (var export : controller.getEntryPoints().keySet()) {
|
||||||
writer.appendFunction("$rt_exports").append(".").append(export).ws().append("=").ws()
|
writer.appendFunction("$rt_exports").append(".").append(export).ws().append("=").ws()
|
||||||
.appendFunction("$rt_export_" + export);
|
.appendFunction("$rt_export_" + export).append(";").softNewLine();
|
||||||
}
|
}
|
||||||
writer.outdent().append("}));").newLine();
|
writer.outdent().append("}));").newLine();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,17 +22,19 @@ import org.teavm.model.MethodReference;
|
||||||
public interface AliasProvider {
|
public interface AliasProvider {
|
||||||
String getFieldAlias(FieldReference field);
|
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 getMethodAlias(MethodDescriptor method);
|
||||||
|
|
||||||
String getClassAlias(String className);
|
ScopedName getClassAlias(String className);
|
||||||
|
|
||||||
String getFunctionAlias(String name);
|
ScopedName getFunctionAlias(String name);
|
||||||
|
|
||||||
String getClassInitAlias(String className);
|
ScopedName getClassInitAlias(String className);
|
||||||
|
|
||||||
|
String getAdditionalScopeName();
|
||||||
|
|
||||||
void reserveName(String name);
|
void reserveName(String name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,24 +17,27 @@ package org.teavm.backend.javascript.codegen;
|
||||||
|
|
||||||
import com.carrotsearch.hppc.ObjectIntHashMap;
|
import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||||
import com.carrotsearch.hppc.ObjectIntMap;
|
import com.carrotsearch.hppc.ObjectIntMap;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
public class DefaultAliasProvider implements AliasProvider {
|
public class DefaultAliasProvider implements AliasProvider {
|
||||||
private final Map<String, String> classAliases = new HashMap<>();
|
private final int maxTopLevelNames;
|
||||||
private final Set<String> knownAliases = new HashSet<>(200, 0.5f);
|
private final Set<String> knownAliases = new HashSet<>(200, 0.5f);
|
||||||
private final ObjectIntMap<String> knowAliasesCounter = new ObjectIntHashMap<>();
|
private final ObjectIntMap<String> knowAliasesCounter = new ObjectIntHashMap<>();
|
||||||
private final Set<String> knownVirtualAliases = new HashSet<>(200, 0.5f);
|
private final Set<String> knownInstanceAliases = new HashSet<>(200, 0.5f);
|
||||||
private final ObjectIntMap<String> knowVirtualAliasesCounter = new ObjectIntHashMap<>();
|
private final ObjectIntMap<String> knowInstanceAliasesCounter = new ObjectIntHashMap<>();
|
||||||
|
private boolean additionalScopeStarted;
|
||||||
|
|
||||||
|
public DefaultAliasProvider(int maxTopLevelNames) {
|
||||||
|
this.maxTopLevelNames = maxTopLevelNames;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getClassAlias(String cls) {
|
public ScopedName getClassAlias(String cls) {
|
||||||
return classAliases.computeIfAbsent(cls, key -> makeUniqueTopLevel(suggestAliasForClass(key)));
|
return makeUnique(suggestAliasForClass(cls));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String suggestAliasForClass(String cls) {
|
private static String suggestAliasForClass(String cls) {
|
||||||
|
@ -84,11 +87,11 @@ public class DefaultAliasProvider implements AliasProvider {
|
||||||
alias = "$" + alias;
|
alias = "$" + alias;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return makeUnique(knownVirtualAliases, knowVirtualAliasesCounter, alias);
|
return makeUniqueInstance(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getStaticMethodAlias(MethodReference method) {
|
public ScopedName getStaticMethodAlias(MethodReference method) {
|
||||||
String suggested = method.getDescriptor().getName();
|
String suggested = method.getDescriptor().getName();
|
||||||
switch (suggested) {
|
switch (suggested) {
|
||||||
case "<init>":
|
case "<init>":
|
||||||
|
@ -99,35 +102,55 @@ public class DefaultAliasProvider implements AliasProvider {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeUniqueTopLevel(getClassAlias(method.getClassName()) + "_" + suggested);
|
return makeUnique(suggestAliasForClass(method.getClassName()) + "_" + suggested);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFieldAlias(FieldReference field) {
|
public String getFieldAlias(FieldReference field) {
|
||||||
return makeUnique(knownVirtualAliases, knowVirtualAliasesCounter, "$" + field.getFieldName());
|
return makeUniqueInstance("$" + field.getFieldName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getStaticFieldAlias(FieldReference field) {
|
public ScopedName getStaticFieldAlias(FieldReference field) {
|
||||||
return makeUniqueTopLevel(getClassAlias(field.getClassName()) + "_" + field.getFieldName());
|
return makeUnique(suggestAliasForClass(field.getClassName()) + "_" + field.getFieldName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFunctionAlias(String name) {
|
public ScopedName getFunctionAlias(String name) {
|
||||||
return name;
|
return makeUnique(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getClassInitAlias(String className) {
|
public ScopedName getClassInitAlias(String className) {
|
||||||
return makeUniqueTopLevel(suggestAliasForClass(className) + "_$callClinit");
|
return makeUnique(suggestAliasForClass(className) + "_$callClinit");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAdditionalScopeName() {
|
||||||
|
return makeUnique("$rt_java").name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reserveName(String name) {
|
public void reserveName(String name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String makeUniqueTopLevel(String suggested) {
|
private ScopedName makeUnique(String suggested) {
|
||||||
return makeUnique(knownAliases, knowAliasesCounter, suggested);
|
suggested = sanitize(suggested);
|
||||||
|
if (!additionalScopeStarted && knownAliases.size() >= maxTopLevelNames) {
|
||||||
|
additionalScopeStarted = true;
|
||||||
|
knownAliases.clear();
|
||||||
|
knowAliasesCounter.clear();
|
||||||
|
}
|
||||||
|
var alias = suggested;
|
||||||
|
int index = knowAliasesCounter.get(alias);
|
||||||
|
if (index > 0) {
|
||||||
|
alias = suggested + index++;
|
||||||
|
}
|
||||||
|
while (!knownAliases.add(alias)) {
|
||||||
|
alias = suggested + index++;
|
||||||
|
}
|
||||||
|
knowAliasesCounter.put(alias, index);
|
||||||
|
return new ScopedName(alias, additionalScopeStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String sanitize(String s) {
|
private String sanitize(String s) {
|
||||||
|
@ -163,17 +186,17 @@ public class DefaultAliasProvider implements AliasProvider {
|
||||||
return isIdentifierStart(c) || c >= '0' && c <= '9';
|
return isIdentifierStart(c) || c >= '0' && c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
private String makeUnique(Set<String> knowAliases, ObjectIntMap<String> indexMap, String alias) {
|
private String makeUniqueInstance(String alias) {
|
||||||
alias = sanitize(alias);
|
alias = sanitize(alias);
|
||||||
String uniqueAlias = alias;
|
String uniqueAlias = alias;
|
||||||
int index = indexMap.get(alias);
|
int index = knowInstanceAliasesCounter.get(alias);
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
uniqueAlias = alias + index++;
|
uniqueAlias = alias + index++;
|
||||||
}
|
}
|
||||||
while (!knowAliases.add(uniqueAlias)) {
|
while (!knownInstanceAliases.add(uniqueAlias)) {
|
||||||
uniqueAlias = alias + index++;
|
uniqueAlias = alias + index++;
|
||||||
}
|
}
|
||||||
indexMap.put(alias, index);
|
knowInstanceAliasesCounter.put(alias, index);
|
||||||
return uniqueAlias;
|
return uniqueAlias;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,13 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||||
private final AliasProvider aliasProvider;
|
private final AliasProvider aliasProvider;
|
||||||
private final ClassReaderSource classSource;
|
private final ClassReaderSource classSource;
|
||||||
private final Map<MethodDescriptor, String> aliases = new HashMap<>();
|
private final Map<MethodDescriptor, String> aliases = new HashMap<>();
|
||||||
private final Map<Key, String> privateAliases = new HashMap<>();
|
private final Map<Key, ScopedName> privateAliases = new HashMap<>();
|
||||||
private final Map<String, String> classAliases = new HashMap<>();
|
private final Map<String, ScopedName> classAliases = new HashMap<>();
|
||||||
private final Map<FieldReference, String> fieldAliases = 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, ScopedName> functionAliases = new HashMap<>();
|
||||||
private final Map<String, String> classInitAliases = new HashMap<>();
|
private final Map<String, ScopedName> classInitAliases = new HashMap<>();
|
||||||
|
private String additionalScopeName;
|
||||||
|
|
||||||
public DefaultNamingStrategy(AliasProvider aliasProvider, ClassReaderSource classSource) {
|
public DefaultNamingStrategy(AliasProvider aliasProvider, ClassReaderSource classSource) {
|
||||||
this.aliasProvider = aliasProvider;
|
this.aliasProvider = aliasProvider;
|
||||||
|
@ -46,12 +47,12 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getNameFor(String cls) {
|
public ScopedName className(String cls) {
|
||||||
return classAliases.computeIfAbsent(cls, key -> aliasProvider.getClassAlias(cls));
|
return classAliases.computeIfAbsent(cls, key -> aliasProvider.getClassAlias(cls));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getNameFor(MethodDescriptor method) {
|
public String instanceMethodName(MethodDescriptor method) {
|
||||||
String alias = aliases.get(method);
|
String alias = aliases.get(method);
|
||||||
if (alias == null) {
|
if (alias == null) {
|
||||||
alias = aliasProvider.getMethodAlias(method);
|
alias = aliasProvider.getMethodAlias(method);
|
||||||
|
@ -61,16 +62,16 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFullNameFor(MethodReference method) {
|
public ScopedName methodName(MethodReference method) {
|
||||||
return getFullNameFor(method, NO_CLASSIFIER);
|
return getFullNameFor(method, NO_CLASSIFIER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getNameForInit(MethodReference method) {
|
public ScopedName initializerName(MethodReference method) {
|
||||||
return getFullNameFor(method, INIT_CLASSIFIER);
|
return getFullNameFor(method, INIT_CLASSIFIER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getFullNameFor(MethodReference method, byte classifier) {
|
private ScopedName getFullNameFor(MethodReference method, byte classifier) {
|
||||||
MethodReference originalMethod = method;
|
MethodReference originalMethod = method;
|
||||||
method = getRealMethod(method);
|
method = getRealMethod(method);
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
|
@ -82,14 +83,14 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getNameFor(FieldReference field) {
|
public String instanceFieldName(FieldReference field) {
|
||||||
String alias = fieldAliases.get(field);
|
String alias = fieldAliases.get(field);
|
||||||
if (alias == null) {
|
if (alias == null) {
|
||||||
FieldReference realField = getRealField(field);
|
FieldReference realField = getRealField(field);
|
||||||
if (realField.equals(field)) {
|
if (realField.equals(field)) {
|
||||||
alias = aliasProvider.getFieldAlias(realField);
|
alias = aliasProvider.getFieldAlias(realField);
|
||||||
} else {
|
} else {
|
||||||
alias = getNameFor(realField);
|
alias = instanceFieldName(realField);
|
||||||
}
|
}
|
||||||
fieldAliases.put(field, alias);
|
fieldAliases.put(field, alias);
|
||||||
}
|
}
|
||||||
|
@ -97,14 +98,14 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFullNameFor(FieldReference field) {
|
public ScopedName fieldName(FieldReference field) {
|
||||||
var alias = staticFieldAliases.get(field);
|
var alias = staticFieldAliases.get(field);
|
||||||
if (alias == null) {
|
if (alias == null) {
|
||||||
FieldReference realField = getRealField(field);
|
FieldReference realField = getRealField(field);
|
||||||
if (realField.equals(field)) {
|
if (realField.equals(field)) {
|
||||||
alias = aliasProvider.getStaticFieldAlias(realField);
|
alias = aliasProvider.getStaticFieldAlias(realField);
|
||||||
} else {
|
} else {
|
||||||
alias = getFullNameFor(realField);
|
alias = fieldName(realField);
|
||||||
}
|
}
|
||||||
staticFieldAliases.put(field, alias);
|
staticFieldAliases.put(field, alias);
|
||||||
}
|
}
|
||||||
|
@ -112,13 +113,21 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getNameForFunction(String name) {
|
public ScopedName functionName(String name) {
|
||||||
return functionAliases.computeIfAbsent(name, key -> aliasProvider.getFunctionAlias(key));
|
return functionAliases.computeIfAbsent(name, aliasProvider::getFunctionAlias);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getNameForClassInit(String className) {
|
public ScopedName classInitializerName(String className) {
|
||||||
return classInitAliases.computeIfAbsent(className, key -> aliasProvider.getClassInitAlias(key));
|
return classInitAliases.computeIfAbsent(className, aliasProvider::getClassInitAlias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String additionalScopeName() {
|
||||||
|
if (additionalScopeName == null) {
|
||||||
|
additionalScopeName = aliasProvider.getAdditionalScopeName();
|
||||||
|
}
|
||||||
|
return additionalScopeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -25,64 +25,80 @@ import org.teavm.model.MethodReference;
|
||||||
public class MinifyingAliasProvider implements AliasProvider {
|
public class MinifyingAliasProvider implements AliasProvider {
|
||||||
private static final String startLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
private static final String startLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
private static final String startVirtualLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
private static final String startVirtualLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
private final int maxTopLevelNames;
|
||||||
private int lastSuffix;
|
private int lastSuffix;
|
||||||
private int lastVirtual;
|
private int lastInstanceSuffix;
|
||||||
|
private int topLevelNames;
|
||||||
|
private boolean additionalScopeStarted;
|
||||||
private final Set<String> usedAliases = new HashSet<>();
|
private final Set<String> usedAliases = new HashSet<>();
|
||||||
private final Set<String> usedVirtualAliases = new HashSet<>();
|
|
||||||
|
|
||||||
@Override
|
public MinifyingAliasProvider(int maxTopLevelNames) {
|
||||||
public String getFieldAlias(FieldReference field) {
|
this.maxTopLevelNames = maxTopLevelNames;
|
||||||
String result;
|
|
||||||
do {
|
|
||||||
result = RenderingUtil.indexToId(lastVirtual++, startVirtualLetters);
|
|
||||||
} while (!usedVirtualAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getStaticFieldAlias(FieldReference field) {
|
public String getFieldAlias(FieldReference field) {
|
||||||
|
return createInstanceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ScopedName getStaticFieldAlias(FieldReference field) {
|
||||||
return createTopLevelName();
|
return createTopLevelName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getStaticMethodAlias(MethodReference method) {
|
public ScopedName getStaticMethodAlias(MethodReference method) {
|
||||||
return createTopLevelName();
|
return createTopLevelName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMethodAlias(MethodDescriptor method) {
|
public String getMethodAlias(MethodDescriptor method) {
|
||||||
String result;
|
return createInstanceName();
|
||||||
do {
|
|
||||||
result = RenderingUtil.indexToId(lastVirtual++, startVirtualLetters);
|
|
||||||
} while (!usedVirtualAliases.add(result) || RenderingUtil.KEYWORDS.contains(result));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getClassAlias(String className) {
|
public ScopedName getClassAlias(String className) {
|
||||||
return createTopLevelName();
|
return createTopLevelName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFunctionAlias(String className) {
|
public ScopedName getFunctionAlias(String className) {
|
||||||
return RenderingUtil.indexToId(lastSuffix++, startLetters);
|
return createTopLevelName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getClassInitAlias(String className) {
|
public ScopedName getClassInitAlias(String className) {
|
||||||
return createTopLevelName();
|
return createTopLevelName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAdditionalScopeName() {
|
||||||
|
return createTopLevelName().name;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reserveName(String name) {
|
public void reserveName(String name) {
|
||||||
usedAliases.add(name);
|
usedAliases.add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createTopLevelName() {
|
private ScopedName createTopLevelName() {
|
||||||
|
if (!additionalScopeStarted && topLevelNames >= maxTopLevelNames) {
|
||||||
|
additionalScopeStarted = true;
|
||||||
|
lastSuffix = 0;
|
||||||
|
}
|
||||||
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 ((!additionalScopeStarted && usedAliases.contains(result)) || RenderingUtil.KEYWORDS.contains(result));
|
||||||
|
++topLevelNames;
|
||||||
|
return new ScopedName(result, additionalScopeStarted);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createInstanceName() {
|
||||||
|
String result;
|
||||||
|
do {
|
||||||
|
result = RenderingUtil.indexToId(lastInstanceSuffix++, startVirtualLetters);
|
||||||
|
} while (RenderingUtil.KEYWORDS.contains(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,21 +20,23 @@ import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
public interface NamingStrategy {
|
public interface NamingStrategy {
|
||||||
String getNameFor(String cls);
|
ScopedName className(String cls);
|
||||||
|
|
||||||
String getNameFor(MethodDescriptor method);
|
String instanceMethodName(MethodDescriptor method);
|
||||||
|
|
||||||
String getNameForInit(MethodReference method);
|
ScopedName initializerName(MethodReference method);
|
||||||
|
|
||||||
String getFullNameFor(MethodReference method);
|
ScopedName methodName(MethodReference method);
|
||||||
|
|
||||||
String getNameFor(FieldReference field);
|
String instanceFieldName(FieldReference field);
|
||||||
|
|
||||||
String getFullNameFor(FieldReference method);
|
ScopedName fieldName(FieldReference method);
|
||||||
|
|
||||||
String getNameForFunction(String name);
|
ScopedName functionName(String name);
|
||||||
|
|
||||||
String getNameForClassInit(String className);
|
ScopedName classInitializerName(String className);
|
||||||
|
|
||||||
|
String additionalScopeName();
|
||||||
|
|
||||||
void reserveName(String name);
|
void reserveName(String name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
public class OutputSourceWriter extends SourceWriter implements LocationProvider {
|
public class OutputSourceWriter extends SourceWriter implements LocationProvider {
|
||||||
|
private static final int LET_SEQUENCE_LIMIT = 50;
|
||||||
private final Appendable innerWriter;
|
private final Appendable innerWriter;
|
||||||
private int indentSize;
|
private int indentSize;
|
||||||
private final NamingStrategy naming;
|
private final NamingStrategy naming;
|
||||||
|
@ -45,6 +46,9 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
private int sectionMarkSection = -1;
|
private int sectionMarkSection = -1;
|
||||||
private int sectionMarkPos;
|
private int sectionMarkPos;
|
||||||
private IntIntMap sectionSizes = new IntIntHashMap();
|
private IntIntMap sectionSizes = new IntIntHashMap();
|
||||||
|
private DeclarationType currentDeclarationType;
|
||||||
|
private boolean expectingDeclarationName;
|
||||||
|
private int letSequenceSize;
|
||||||
|
|
||||||
OutputSourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) {
|
OutputSourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) {
|
||||||
this.naming = naming;
|
this.naming = naming;
|
||||||
|
@ -61,9 +65,31 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
this.minified = minified;
|
this.minified = minified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void finish() {
|
||||||
|
finishLet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finishLetImplicitly() {
|
||||||
|
if (currentDeclarationType == null) {
|
||||||
|
finishLet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finishLet() {
|
||||||
|
if (letSequenceSize > 0) {
|
||||||
|
letSequenceSize = 0;
|
||||||
|
try {
|
||||||
|
innerWriter.append(";\n");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter append(char value) {
|
public SourceWriter append(char value) {
|
||||||
appendIndent();
|
appendIndent();
|
||||||
|
finishLetImplicitly();
|
||||||
try {
|
try {
|
||||||
innerWriter.append(value);
|
innerWriter.append(value);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -96,6 +122,7 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
if (start == end) {
|
if (start == end) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
finishLetImplicitly();
|
||||||
appendIndent();
|
appendIndent();
|
||||||
column += end - start;
|
column += end - start;
|
||||||
offset += end - start;
|
offset += end - start;
|
||||||
|
@ -108,32 +135,32 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendClass(String cls) {
|
public SourceWriter appendClass(String cls) {
|
||||||
return appendName(naming.getNameFor(cls));
|
return appendDeclaration(naming.className(cls));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendField(FieldReference field) {
|
public SourceWriter appendField(FieldReference field) {
|
||||||
return append(naming.getNameFor(field));
|
return append(naming.instanceFieldName(field));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendStaticField(FieldReference field) {
|
public SourceWriter appendStaticField(FieldReference field) {
|
||||||
return appendName(naming.getFullNameFor(field));
|
return appendDeclaration(naming.fieldName(field));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendMethod(MethodDescriptor method) {
|
public SourceWriter appendVirtualMethod(MethodDescriptor method) {
|
||||||
return append(naming.getNameFor(method));
|
return append(naming.instanceMethodName(method));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendMethodBody(MethodReference method) {
|
public SourceWriter appendMethod(MethodReference method) {
|
||||||
return appendName(naming.getFullNameFor(method));
|
return appendDeclaration(naming.methodName(method));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendFunction(String name) {
|
public SourceWriter appendFunction(String name) {
|
||||||
return append(naming.getNameForFunction(name));
|
return appendDeclaration(naming.functionName(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -143,16 +170,117 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendInit(MethodReference method) {
|
public SourceWriter appendInit(MethodReference method) {
|
||||||
return appendName(naming.getNameForInit(method));
|
return appendDeclaration(naming.initializerName(method));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendClassInit(String className) {
|
public SourceWriter appendClassInit(String className) {
|
||||||
return appendName(naming.getNameForClassInit(className));
|
return appendDeclaration(naming.classInitializerName(className));
|
||||||
}
|
}
|
||||||
|
|
||||||
private SourceWriter appendName(String name) {
|
@Override
|
||||||
append(name);
|
public SourceWriter startVariableDeclaration() {
|
||||||
|
checkStartDeclaration();
|
||||||
|
currentDeclarationType = DeclarationType.VARIABLE;
|
||||||
|
expectingDeclarationName = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceWriter startFunctionDeclaration() {
|
||||||
|
checkStartDeclaration();
|
||||||
|
currentDeclarationType = DeclarationType.FUNCTION;
|
||||||
|
expectingDeclarationName = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceWriter declareVariable() {
|
||||||
|
checkStartDeclaration();
|
||||||
|
currentDeclarationType = DeclarationType.VARIABLE_WITHOUT_VALUE;
|
||||||
|
expectingDeclarationName = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkStartDeclaration() {
|
||||||
|
if (currentDeclarationType != null) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceWriter endDeclaration() {
|
||||||
|
if (currentDeclarationType == null || expectingDeclarationName) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
switch (currentDeclarationType) {
|
||||||
|
case FUNCTION:
|
||||||
|
newLine();
|
||||||
|
break;
|
||||||
|
case VARIABLE:
|
||||||
|
if (letSequenceSize == 0) {
|
||||||
|
append(';').softNewLine();
|
||||||
|
} else if (letSequenceSize >= LET_SEQUENCE_LIMIT) {
|
||||||
|
finishLet();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VARIABLE_WITHOUT_VALUE:
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
currentDeclarationType = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SourceWriter appendDeclaration(ScopedName name) {
|
||||||
|
if (!expectingDeclarationName) {
|
||||||
|
return appendName(name);
|
||||||
|
}
|
||||||
|
expectingDeclarationName = false;
|
||||||
|
switch (currentDeclarationType) {
|
||||||
|
case FUNCTION:
|
||||||
|
finishLet();
|
||||||
|
if (name.scoped) {
|
||||||
|
append(naming.additionalScopeName()).append('.').append(name.name).ws()
|
||||||
|
.append('=').ws().append("function");
|
||||||
|
} else {
|
||||||
|
append("function ").append(name.name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VARIABLE:
|
||||||
|
if (name.scoped) {
|
||||||
|
finishLet();
|
||||||
|
append(naming.additionalScopeName()).append('.');
|
||||||
|
} else {
|
||||||
|
if (letSequenceSize++ == 0) {
|
||||||
|
append("let ");
|
||||||
|
} else {
|
||||||
|
append(',').softNewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
append(name.name).ws().append('=').ws();
|
||||||
|
break;
|
||||||
|
case VARIABLE_WITHOUT_VALUE:
|
||||||
|
if (!name.scoped) {
|
||||||
|
if (letSequenceSize++ == 0) {
|
||||||
|
append("let ");
|
||||||
|
} else {
|
||||||
|
append(',').softNewLine();
|
||||||
|
}
|
||||||
|
append(name.name);
|
||||||
|
}
|
||||||
|
expectingDeclarationName = false;
|
||||||
|
currentDeclarationType = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SourceWriter appendName(ScopedName name) {
|
||||||
|
if (name.scoped) {
|
||||||
|
append(naming.additionalScopeName());
|
||||||
|
append('.');
|
||||||
|
}
|
||||||
|
append(name.name);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +288,7 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
if (minified) {
|
if (minified) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
finishLetImplicitly();
|
||||||
if (lineStart) {
|
if (lineStart) {
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < indentSize; ++i) {
|
for (int i = 0; i < indentSize; ++i) {
|
||||||
|
@ -176,6 +305,7 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter newLine() {
|
public SourceWriter newLine() {
|
||||||
|
finishLetImplicitly();
|
||||||
try {
|
try {
|
||||||
innerWriter.append('\n');
|
innerWriter.append('\n');
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -194,6 +324,7 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
newLine();
|
newLine();
|
||||||
} else {
|
} else {
|
||||||
if (!minified) {
|
if (!minified) {
|
||||||
|
finishLetImplicitly();
|
||||||
try {
|
try {
|
||||||
innerWriter.append(' ');
|
innerWriter.append(' ');
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -209,6 +340,7 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter sameLineWs() {
|
public SourceWriter sameLineWs() {
|
||||||
if (!minified) {
|
if (!minified) {
|
||||||
|
finishLetImplicitly();
|
||||||
try {
|
try {
|
||||||
innerWriter.append(' ');
|
innerWriter.append(' ');
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -231,6 +363,7 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter softNewLine() {
|
public SourceWriter softNewLine() {
|
||||||
if (!minified) {
|
if (!minified) {
|
||||||
|
finishLetImplicitly();
|
||||||
try {
|
try {
|
||||||
innerWriter.append('\n');
|
innerWriter.append('\n');
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -362,4 +495,10 @@ public class OutputSourceWriter extends SourceWriter implements LocationProvider
|
||||||
public int getSectionSize(int sectionId) {
|
public int getSectionSize(int sectionId) {
|
||||||
return sectionSizes.get(sectionId);
|
return sectionSizes.get(sectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum DeclarationType {
|
||||||
|
FUNCTION,
|
||||||
|
VARIABLE,
|
||||||
|
VARIABLE_WITHOUT_VALUE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,14 +88,14 @@ public class RememberedSource implements SourceFragment {
|
||||||
|
|
||||||
case RememberingSourceWriter.METHOD:
|
case RememberingSourceWriter.METHOD:
|
||||||
if ((filter & FILTER_REF) != 0) {
|
if ((filter & FILTER_REF) != 0) {
|
||||||
sink.appendMethod(methodDescriptors[intArgs[intArgIndex]]);
|
sink.appendVirtualMethod(methodDescriptors[intArgs[intArgIndex]]);
|
||||||
}
|
}
|
||||||
intArgIndex++;
|
intArgIndex++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RememberingSourceWriter.METHOD_BODY:
|
case RememberingSourceWriter.METHOD_BODY:
|
||||||
if ((filter & FILTER_REF) != 0) {
|
if ((filter & FILTER_REF) != 0) {
|
||||||
sink.appendMethodBody(methods[intArgs[intArgIndex]]);
|
sink.appendMethod(methods[intArgs[intArgIndex]]);
|
||||||
}
|
}
|
||||||
intArgIndex++;
|
intArgIndex++;
|
||||||
break;
|
break;
|
||||||
|
@ -170,6 +170,27 @@ public class RememberedSource implements SourceFragment {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RememberingSourceWriter.START_FUNCTION:
|
||||||
|
if ((filter & FILTER_TEXT) != 0) {
|
||||||
|
sink.startFunctionDeclaration();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RememberingSourceWriter.START_VARIABLE:
|
||||||
|
if ((filter & FILTER_TEXT) != 0) {
|
||||||
|
sink.startVariableDeclaration();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RememberingSourceWriter.END_DECLARATION:
|
||||||
|
if ((filter & FILTER_TEXT) != 0) {
|
||||||
|
sink.endDeclaration();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RememberingSourceWriter.DECLARE_VARIABLE:
|
||||||
|
if ((filter & FILTER_TEXT) != 0) {
|
||||||
|
sink.declareVariable();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case RememberingSourceWriter.EMIT_LOCATION:
|
case RememberingSourceWriter.EMIT_LOCATION:
|
||||||
if ((filter & FILTER_DEBUG) != 0) {
|
if ((filter & FILTER_DEBUG) != 0) {
|
||||||
var fileIndex = intArgs[intArgIndex];
|
var fileIndex = intArgs[intArgIndex];
|
||||||
|
|
|
@ -42,6 +42,10 @@ public class RememberingSourceWriter extends SourceWriter {
|
||||||
static final byte SOFT_NEW_LINE = 12;
|
static final byte SOFT_NEW_LINE = 12;
|
||||||
static final byte INDENT = 13;
|
static final byte INDENT = 13;
|
||||||
static final byte OUTDENT = 14;
|
static final byte OUTDENT = 14;
|
||||||
|
static final byte START_FUNCTION = 27;
|
||||||
|
static final byte START_VARIABLE = 28;
|
||||||
|
static final byte END_DECLARATION = 29;
|
||||||
|
static final byte DECLARE_VARIABLE = 30;
|
||||||
static final byte EMIT_LOCATION = 15;
|
static final byte EMIT_LOCATION = 15;
|
||||||
static final byte ENTER_LOCATION = 16;
|
static final byte ENTER_LOCATION = 16;
|
||||||
static final byte EXIT_LOCATION = 17;
|
static final byte EXIT_LOCATION = 17;
|
||||||
|
@ -73,6 +77,8 @@ public class RememberingSourceWriter extends SourceWriter {
|
||||||
private List<MethodReference> methods = new ArrayList<>();
|
private List<MethodReference> methods = new ArrayList<>();
|
||||||
private ObjectIntMap<MethodReference> methodIndexes = new ObjectIntHashMap<>();
|
private ObjectIntMap<MethodReference> methodIndexes = new ObjectIntHashMap<>();
|
||||||
|
|
||||||
|
private boolean isInDeclaration;
|
||||||
|
|
||||||
public RememberingSourceWriter(boolean debug) {
|
public RememberingSourceWriter(boolean debug) {
|
||||||
this.debug = debug;
|
this.debug = debug;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +135,7 @@ public class RememberingSourceWriter extends SourceWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendMethod(MethodDescriptor method) {
|
public SourceWriter appendVirtualMethod(MethodDescriptor method) {
|
||||||
flush();
|
flush();
|
||||||
commands.add(METHOD);
|
commands.add(METHOD);
|
||||||
appendMethodDescriptorArg(method);
|
appendMethodDescriptorArg(method);
|
||||||
|
@ -137,7 +143,7 @@ public class RememberingSourceWriter extends SourceWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter appendMethodBody(MethodReference method) {
|
public SourceWriter appendMethod(MethodReference method) {
|
||||||
flush();
|
flush();
|
||||||
commands.add(METHOD_BODY);
|
commands.add(METHOD_BODY);
|
||||||
appendMethodArg(method);
|
appendMethodArg(method);
|
||||||
|
@ -225,6 +231,49 @@ public class RememberingSourceWriter extends SourceWriter {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceWriter startFunctionDeclaration() {
|
||||||
|
checkNotInDeclaration();
|
||||||
|
isInDeclaration = true;
|
||||||
|
flush();
|
||||||
|
commands.add(START_FUNCTION);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceWriter startVariableDeclaration() {
|
||||||
|
checkNotInDeclaration();
|
||||||
|
isInDeclaration = true;
|
||||||
|
flush();
|
||||||
|
commands.add(START_VARIABLE);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNotInDeclaration() {
|
||||||
|
if (isInDeclaration) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceWriter endDeclaration() {
|
||||||
|
if (!isInDeclaration) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
isInDeclaration = false;
|
||||||
|
flush();
|
||||||
|
commands.add(END_DECLARATION);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceWriter declareVariable() {
|
||||||
|
checkNotInDeclaration();
|
||||||
|
flush();
|
||||||
|
commands.add(DECLARE_VARIABLE);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriter emitLocation(String fileName, int line) {
|
public SourceWriter emitLocation(String fileName, int line) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 konsoletyper.
|
||||||
|
*
|
||||||
|
* 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 String name;
|
||||||
|
public final boolean scoped;
|
||||||
|
|
||||||
|
public ScopedName(String name, boolean scoped) {
|
||||||
|
this.name = name;
|
||||||
|
this.scoped = scoped;
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,26 +76,38 @@ public abstract class SourceWriter implements Appendable, SourceWriterSink {
|
||||||
public abstract SourceWriter appendStaticField(FieldReference field);
|
public abstract SourceWriter appendStaticField(FieldReference field);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract SourceWriter appendMethod(MethodDescriptor method);
|
public abstract SourceWriter appendVirtualMethod(MethodDescriptor method);
|
||||||
|
|
||||||
public SourceWriter appendMethod(String name, Class<?>... params) {
|
public SourceWriter appendVirtualMethod(String name, Class<?>... params) {
|
||||||
return appendMethod(new MethodDescriptor(name, params));
|
return appendVirtualMethod(new MethodDescriptor(name, params));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract SourceWriter appendMethodBody(MethodReference method);
|
public abstract SourceWriter appendMethod(MethodReference method);
|
||||||
|
|
||||||
public SourceWriter appendMethodBody(String className, String name, ValueType... params) {
|
public SourceWriter appendMethod(String className, String name, ValueType... params) {
|
||||||
return appendMethodBody(new MethodReference(className, new MethodDescriptor(name, params)));
|
return appendMethod(new MethodReference(className, new MethodDescriptor(name, params)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceWriter appendMethodBody(Class<?> cls, String name, Class<?>... params) {
|
public SourceWriter appendMethod(Class<?> cls, String name, Class<?>... params) {
|
||||||
return appendMethodBody(new MethodReference(cls, name, params));
|
return appendMethod(new MethodReference(cls, name, params));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract SourceWriter appendFunction(String name);
|
public abstract SourceWriter appendFunction(String name);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract SourceWriter startFunctionDeclaration();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract SourceWriter startVariableDeclaration();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract SourceWriter endDeclaration();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract SourceWriter declareVariable();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract SourceWriter appendGlobal(String name);
|
public abstract SourceWriter appendGlobal(String name);
|
||||||
|
|
||||||
|
|
|
@ -36,11 +36,27 @@ public interface SourceWriterSink {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
default SourceWriterSink appendMethod(MethodDescriptor method) {
|
default SourceWriterSink appendVirtualMethod(MethodDescriptor method) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
default SourceWriterSink appendMethodBody(MethodReference method) {
|
default SourceWriterSink appendMethod(MethodReference method) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
default SourceWriterSink startVariableDeclaration() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
default SourceWriterSink startFunctionDeclaration() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
default SourceWriterSink endDeclaration() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
default SourceWriterSink declareVariable() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,12 +98,18 @@ public class AstWriter {
|
||||||
private Set<String> aliases = new HashSet<>();
|
private Set<String> aliases = new HashSet<>();
|
||||||
private Function<String, NameEmitter> globalNameWriter;
|
private Function<String, NameEmitter> globalNameWriter;
|
||||||
public final Map<String, Scope> currentScopes = new HashMap<>();
|
public final Map<String, Scope> currentScopes = new HashMap<>();
|
||||||
|
protected final Set<Scope> topLevelScopes = new HashSet<>();
|
||||||
|
private boolean inFunction;
|
||||||
|
|
||||||
public AstWriter(SourceWriter writer, Function<String, NameEmitter> globalNameWriter) {
|
public AstWriter(SourceWriter writer, Function<String, NameEmitter> globalNameWriter) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
this.globalNameWriter = globalNameWriter;
|
this.globalNameWriter = globalNameWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final boolean inFunction() {
|
||||||
|
return inFunction;
|
||||||
|
}
|
||||||
|
|
||||||
public void declareName(String name) {
|
public void declareName(String name) {
|
||||||
if (nameMap.containsKey(name)) {
|
if (nameMap.containsKey(name)) {
|
||||||
return;
|
return;
|
||||||
|
@ -125,10 +131,6 @@ public class AstWriter {
|
||||||
nameMap.put(name, emitter);
|
nameMap.put(name, emitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hoist(Object node) {
|
|
||||||
hoist((AstNode) node);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void hoist(AstNode node) {
|
public void hoist(AstNode node) {
|
||||||
declareName("arguments");
|
declareName("arguments");
|
||||||
node.visit(n -> {
|
node.visit(n -> {
|
||||||
|
@ -162,11 +164,11 @@ public class AstWriter {
|
||||||
print((AstNode) node, precedence);
|
print((AstNode) node, precedence);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void print(AstNode node) {
|
public boolean print(AstNode node) {
|
||||||
print(node, PRECEDENCE_COMMA);
|
return print(node, PRECEDENCE_COMMA);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void print(AstNode node, int precedence) {
|
public boolean print(AstNode node, int precedence) {
|
||||||
switch (node.getType()) {
|
switch (node.getType()) {
|
||||||
case Token.SCRIPT:
|
case Token.SCRIPT:
|
||||||
print((AstRoot) node);
|
print((AstRoot) node);
|
||||||
|
@ -176,8 +178,7 @@ public class AstWriter {
|
||||||
print((FunctionCall) node, precedence);
|
print((FunctionCall) node, precedence);
|
||||||
break;
|
break;
|
||||||
case Token.FUNCTION:
|
case Token.FUNCTION:
|
||||||
print((FunctionNode) node);
|
return print((FunctionNode) node);
|
||||||
break;
|
|
||||||
case Token.ARRAYCOMP:
|
case Token.ARRAYCOMP:
|
||||||
print((ArrayComprehension) node);
|
print((ArrayComprehension) node);
|
||||||
break;
|
break;
|
||||||
|
@ -287,8 +288,7 @@ public class AstWriter {
|
||||||
case Token.CONST:
|
case Token.CONST:
|
||||||
case Token.VAR:
|
case Token.VAR:
|
||||||
case Token.LET:
|
case Token.LET:
|
||||||
print((VariableDeclaration) node);
|
return print((VariableDeclaration) node);
|
||||||
break;
|
|
||||||
case Token.WHILE:
|
case Token.WHILE:
|
||||||
print((WhileLoop) node);
|
print((WhileLoop) node);
|
||||||
break;
|
break;
|
||||||
|
@ -302,20 +302,23 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(AstRoot node) {
|
private void print(AstRoot node) {
|
||||||
for (Node child : node) {
|
for (Node child : node) {
|
||||||
print((AstNode) child);
|
if (!print((AstNode) child)) {
|
||||||
writer.softNewLine();
|
writer.softNewLine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(Block node) {
|
private void print(Block node) {
|
||||||
writer.append('{').softNewLine().indent();
|
writer.append('{').softNewLine().indent();
|
||||||
for (Node child = node.getFirstChild(); child != null; child = child.getNext()) {
|
for (Node child = node.getFirstChild(); child != null; child = child.getNext()) {
|
||||||
print((AstNode) child);
|
if (!print((AstNode) child)) {
|
||||||
writer.softNewLine();
|
writer.softNewLine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writer.outdent().append('}');
|
writer.outdent().append('}');
|
||||||
}
|
}
|
||||||
|
@ -324,8 +327,9 @@ public class AstWriter {
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node);
|
||||||
writer.append('{').softNewLine().indent();
|
writer.append('{').softNewLine().indent();
|
||||||
for (Node child = node.getFirstChild(); child != null; child = child.getNext()) {
|
for (Node child = node.getFirstChild(); child != null; child = child.getNext()) {
|
||||||
print((AstNode) child);
|
if (!print((AstNode) child)) {
|
||||||
writer.softNewLine();
|
writer.softNewLine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writer.outdent().append('}');
|
writer.outdent().append('}');
|
||||||
leaveScope(scope, node);
|
leaveScope(scope, node);
|
||||||
|
@ -456,7 +460,7 @@ public class AstWriter {
|
||||||
print(node.getTryBlock());
|
print(node.getTryBlock());
|
||||||
for (CatchClause cc : node.getCatchClauses()) {
|
for (CatchClause cc : node.getCatchClauses()) {
|
||||||
writer.ws().append("catch").ws().append('(');
|
writer.ws().append("catch").ws().append('(');
|
||||||
print(cc.getVarName());
|
writer.append(cc.getVarName().getIdentifier());
|
||||||
if (cc.getCatchCondition() != null) {
|
if (cc.getCatchCondition() != null) {
|
||||||
writer.append(" if ");
|
writer.append(" if ");
|
||||||
print(cc.getCatchCondition());
|
print(cc.getCatchCondition());
|
||||||
|
@ -470,7 +474,15 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(VariableDeclaration node) {
|
private boolean print(VariableDeclaration node) {
|
||||||
|
if (isTopLevel() && node.getVariables().get(0).getTarget() instanceof Name) {
|
||||||
|
var name = (Name) node.getVariables().get(0).getTarget();
|
||||||
|
var definingScope = scopeOfId(name.getIdentifier());
|
||||||
|
if (definingScope == null || topLevelScopes.contains(definingScope)) {
|
||||||
|
printTopLevel(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
switch (node.getType()) {
|
switch (node.getType()) {
|
||||||
case Token.VAR:
|
case Token.VAR:
|
||||||
writer.append("var ");
|
writer.append("var ");
|
||||||
|
@ -492,6 +504,23 @@ public class AstWriter {
|
||||||
if (node.isStatement()) {
|
if (node.isStatement()) {
|
||||||
writer.append(';');
|
writer.append(';');
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printTopLevel(VariableDeclaration node) {
|
||||||
|
for (var variable : node.getVariables()) {
|
||||||
|
var target = variable.getTarget();
|
||||||
|
if (target instanceof Name) {
|
||||||
|
var id = ((Name) target).getIdentifier();
|
||||||
|
if (variable.getInitializer() != null) {
|
||||||
|
writer.startVariableDeclaration().appendFunction(id);
|
||||||
|
print(variable.getInitializer());
|
||||||
|
writer.endDeclaration();
|
||||||
|
} else {
|
||||||
|
writer.declareVariable().appendFunction(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(VariableInitializer node) {
|
private void print(VariableInitializer node) {
|
||||||
|
@ -575,7 +604,7 @@ public class AstWriter {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.appendMethodBody(method).append('(');
|
writer.appendMethod(method).append('(');
|
||||||
printList(node.getArguments());
|
printList(node.getArguments());
|
||||||
writer.append(')');
|
writer.append(')');
|
||||||
return true;
|
return true;
|
||||||
|
@ -722,9 +751,18 @@ public class AstWriter {
|
||||||
print(node.getRight());
|
print(node.getRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void print(FunctionNode node) {
|
protected boolean print(FunctionNode node) {
|
||||||
var scope = enterScope(node);
|
|
||||||
var isArrow = node.getFunctionType() == FunctionNode.ARROW_FUNCTION;
|
var isArrow = node.getFunctionType() == FunctionNode.ARROW_FUNCTION;
|
||||||
|
if (isTopLevel() && !isArrow && node.getFunctionName() != null) {
|
||||||
|
var definingScope = scopeOfId(node.getFunctionName().getIdentifier());
|
||||||
|
if (definingScope == null || topLevelScopes.contains(definingScope)) {
|
||||||
|
printTopLevel(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var wasInFunction = inFunction;
|
||||||
|
inFunction = true;
|
||||||
|
var scope = enterScope(node);
|
||||||
if (!isArrow) {
|
if (!isArrow) {
|
||||||
currentScopes.put("arguments", node);
|
currentScopes.put("arguments", node);
|
||||||
}
|
}
|
||||||
|
@ -760,6 +798,23 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
leaveScope(scope, node);
|
leaveScope(scope, node);
|
||||||
|
inFunction = wasInFunction;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printTopLevel(FunctionNode node) {
|
||||||
|
var wasInFunction = inFunction;
|
||||||
|
inFunction = true;
|
||||||
|
var scope = enterScope(node);
|
||||||
|
currentScopes.put("arguments", node);
|
||||||
|
writer.startFunctionDeclaration().appendFunction(node.getFunctionName().getIdentifier());
|
||||||
|
writer.append('(');
|
||||||
|
printList(node.getParams());
|
||||||
|
writer.append(')').ws();
|
||||||
|
print(node.getBody());
|
||||||
|
writer.endDeclaration();
|
||||||
|
leaveScope(scope, node);
|
||||||
|
inFunction = wasInFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(LetNode node) {
|
private void print(LetNode node) {
|
||||||
|
@ -980,6 +1035,9 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onEnterScope(Scope scope) {
|
protected void onEnterScope(Scope scope) {
|
||||||
|
if (isTopLevel() && !inFunction()) {
|
||||||
|
topLevelScopes.add(scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void leaveScope(Map<String, Scope> backup, Scope scope) {
|
private void leaveScope(Map<String, Scope> backup, Scope scope) {
|
||||||
|
@ -994,9 +1052,16 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onLeaveScope(Scope scope) {
|
protected void onLeaveScope(Scope scope) {
|
||||||
|
if (isTopLevel() && !inFunction()) {
|
||||||
|
topLevelScopes.remove(scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Scope scopeOfId(String id) {
|
protected Scope scopeOfId(String id) {
|
||||||
return currentScopes.get(id);
|
return currentScopes.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isTopLevel() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,7 @@ public class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
||||||
statementRenderer.setCurrentPart(0);
|
statementRenderer.setCurrentPart(0);
|
||||||
|
|
||||||
if (method.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
if (method.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
||||||
writer.appendMethodBody(NameFrequencyEstimator.MONITOR_ENTER_SYNC_METHOD);
|
writer.appendMethod(NameFrequencyEstimator.MONITOR_ENTER_SYNC_METHOD);
|
||||||
writer.append("(");
|
writer.append("(");
|
||||||
appendMonitor(statementRenderer, method);
|
appendMonitor(statementRenderer, method);
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
|
@ -168,7 +168,7 @@ public class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
||||||
if (method.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
if (method.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
||||||
writer.outdent().append("}").ws().append("finally").ws().append("{").indent().softNewLine();
|
writer.outdent().append("}").ws().append("finally").ws().append("{").indent().softNewLine();
|
||||||
|
|
||||||
writer.appendMethodBody(NameFrequencyEstimator.MONITOR_EXIT_SYNC_METHOD);
|
writer.appendMethod(NameFrequencyEstimator.MONITOR_EXIT_SYNC_METHOD);
|
||||||
writer.append("(");
|
writer.append("(");
|
||||||
appendMonitor(statementRenderer, method);
|
appendMonitor(statementRenderer, method);
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
|
@ -242,7 +242,7 @@ public class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
||||||
for (int i = 0; i < methodNode.getBody().size(); ++i) {
|
for (int i = 0; i < methodNode.getBody().size(); ++i) {
|
||||||
writer.append("case ").append(i).append(":").indent().softNewLine();
|
writer.append("case ").append(i).append(":").indent().softNewLine();
|
||||||
if (i == 0 && methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
if (i == 0 && methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
||||||
writer.appendMethodBody(NameFrequencyEstimator.MONITOR_ENTER_METHOD);
|
writer.appendMethod(NameFrequencyEstimator.MONITOR_ENTER_METHOD);
|
||||||
writer.append("(");
|
writer.append("(");
|
||||||
appendMonitor(statementRenderer, methodNode);
|
appendMonitor(statementRenderer, methodNode);
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
|
@ -260,7 +260,7 @@ public class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
||||||
writer.outdent().append("}").ws().append("finally").ws().append('{').indent().softNewLine();
|
writer.outdent().append("}").ws().append("finally").ws().append('{').indent().softNewLine();
|
||||||
writer.append("if").ws().append("(!").appendFunction("$rt_suspending").append("())")
|
writer.append("if").ws().append("(!").appendFunction("$rt_suspending").append("())")
|
||||||
.ws().append("{").indent().softNewLine();
|
.ws().append("{").indent().softNewLine();
|
||||||
writer.appendMethodBody(NameFrequencyEstimator.MONITOR_EXIT_METHOD).append("(");
|
writer.appendMethod(NameFrequencyEstimator.MONITOR_EXIT_METHOD).append("(");
|
||||||
appendMonitor(statementRenderer, methodNode);
|
appendMonitor(statementRenderer, methodNode);
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
writer.outdent().append('}').softNewLine();
|
writer.outdent().append('}').softNewLine();
|
||||||
|
|
|
@ -38,6 +38,11 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
|
|
||||||
private Map<String, Entry> entries = new HashMap<>();
|
private Map<String, Entry> entries = new HashMap<>();
|
||||||
private Set<String> reservedNames = new HashSet<>();
|
private Set<String> reservedNames = new HashSet<>();
|
||||||
|
private boolean hasAdditionalScope;
|
||||||
|
|
||||||
|
public boolean hasAdditionalScope() {
|
||||||
|
return hasAdditionalScope;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriterSink appendClass(String cls) {
|
public SourceWriterSink appendClass(String cls) {
|
||||||
|
@ -45,7 +50,7 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
var entry = entries.get(key);
|
var entry = entries.get(key);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new Entry();
|
entry = new Entry();
|
||||||
entry.operation = naming -> naming.getNameFor(cls);
|
entry.operation = naming -> naming.className(cls).scoped;
|
||||||
entries.put(key, entry);
|
entries.put(key, entry);
|
||||||
}
|
}
|
||||||
entry.frequency++;
|
entry.frequency++;
|
||||||
|
@ -58,7 +63,10 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
var entry = entries.get(key);
|
var entry = entries.get(key);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new Entry();
|
entry = new Entry();
|
||||||
entry.operation = naming -> naming.getNameFor(field);
|
entry.operation = naming -> {
|
||||||
|
naming.instanceFieldName(field);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
entries.put(key, entry);
|
entries.put(key, entry);
|
||||||
}
|
}
|
||||||
entry.frequency++;
|
entry.frequency++;
|
||||||
|
@ -71,7 +79,7 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
var entry = entries.get(key);
|
var entry = entries.get(key);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new Entry();
|
entry = new Entry();
|
||||||
entry.operation = naming -> naming.getFullNameFor(field);
|
entry.operation = naming -> naming.fieldName(field).scoped;
|
||||||
entries.put(key, entry);
|
entries.put(key, entry);
|
||||||
}
|
}
|
||||||
entry.frequency++;
|
entry.frequency++;
|
||||||
|
@ -79,12 +87,15 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriterSink appendMethod(MethodDescriptor method) {
|
public SourceWriterSink appendVirtualMethod(MethodDescriptor method) {
|
||||||
var key = "r:" + method;
|
var key = "r:" + method;
|
||||||
var entry = entries.get(key);
|
var entry = entries.get(key);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new Entry();
|
entry = new Entry();
|
||||||
entry.operation = naming -> naming.getNameFor(method);
|
entry.operation = naming -> {
|
||||||
|
naming.instanceMethodName(method);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
entries.put(key, entry);
|
entries.put(key, entry);
|
||||||
}
|
}
|
||||||
entry.frequency++;
|
entry.frequency++;
|
||||||
|
@ -92,12 +103,12 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SourceWriterSink appendMethodBody(MethodReference method) {
|
public SourceWriterSink appendMethod(MethodReference method) {
|
||||||
var key = "R:" + method;
|
var key = "R:" + method;
|
||||||
var entry = entries.get(key);
|
var entry = entries.get(key);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new Entry();
|
entry = new Entry();
|
||||||
entry.operation = naming -> naming.getFullNameFor(method);
|
entry.operation = naming -> naming.methodName(method).scoped;
|
||||||
entries.put(key, entry);
|
entries.put(key, entry);
|
||||||
}
|
}
|
||||||
entry.frequency++;
|
entry.frequency++;
|
||||||
|
@ -110,7 +121,7 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
var entry = entries.get(key);
|
var entry = entries.get(key);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new Entry();
|
entry = new Entry();
|
||||||
entry.operation = naming -> naming.getNameForFunction(name);
|
entry.operation = naming -> naming.functionName(name).scoped;
|
||||||
entries.put(key, entry);
|
entries.put(key, entry);
|
||||||
}
|
}
|
||||||
entry.frequency++;
|
entry.frequency++;
|
||||||
|
@ -129,7 +140,7 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
var entry = entries.get(key);
|
var entry = entries.get(key);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new Entry();
|
entry = new Entry();
|
||||||
entry.operation = naming -> naming.getNameForInit(method);
|
entry.operation = naming -> naming.initializerName(method).scoped;
|
||||||
entries.put(key, entry);
|
entries.put(key, entry);
|
||||||
}
|
}
|
||||||
entry.frequency++;
|
entry.frequency++;
|
||||||
|
@ -142,7 +153,7 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
var entry = entries.get(key);
|
var entry = entries.get(key);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new Entry();
|
entry = new Entry();
|
||||||
entry.operation = naming -> naming.getNameForClassInit(className);
|
entry.operation = naming -> naming.classInitializerName(className).scoped;
|
||||||
entries.put(key, entry);
|
entries.put(key, entry);
|
||||||
}
|
}
|
||||||
entry.frequency++;
|
entry.frequency++;
|
||||||
|
@ -156,7 +167,7 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
var entryList = new ArrayList<>(entries.values());
|
var entryList = new ArrayList<>(entries.values());
|
||||||
entryList.sort((o1, o2) -> Integer.compare(o2.frequency, o1.frequency));
|
entryList.sort((o1, o2) -> Integer.compare(o2.frequency, o1.frequency));
|
||||||
for (var entry : entryList) {
|
for (var entry : entryList) {
|
||||||
entry.operation.perform(naming);
|
hasAdditionalScope |= entry.operation.perform(naming);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +177,6 @@ public class NameFrequencyEstimator implements SourceWriterSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface NamingOperation {
|
private interface NamingOperation {
|
||||||
void perform(NamingStrategy naming);
|
boolean perform(NamingStrategy naming);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,7 +188,7 @@ public class Renderer implements RenderingManager {
|
||||||
writer.appendClass("java.lang.Object").append(".prototype.toString").ws().append("=").ws()
|
writer.appendClass("java.lang.Object").append(".prototype.toString").ws().append("=").ws()
|
||||||
.append("function()").ws().append("{").indent().softNewLine();
|
.append("function()").ws().append("{").indent().softNewLine();
|
||||||
writer.append("return ").appendFunction("$rt_ustr").append("(")
|
writer.append("return ").appendFunction("$rt_ustr").append("(")
|
||||||
.appendMethodBody(Object.class, "toString", String.class).append("(this));")
|
.appendMethod(Object.class, "toString", String.class).append("(this));")
|
||||||
.softNewLine();
|
.softNewLine();
|
||||||
writer.outdent().append("};").newLine();
|
writer.outdent().append("};").newLine();
|
||||||
}
|
}
|
||||||
|
@ -265,7 +265,6 @@ public class Renderer implements RenderingManager {
|
||||||
renderFullClassFunctionDeclaration(cls, nonStaticFields);
|
renderFullClassFunctionDeclaration(cls, nonStaticFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasLet = false;
|
|
||||||
for (FieldHolder field : staticFields) {
|
for (FieldHolder field : staticFields) {
|
||||||
Object value = field.getInitialValue();
|
Object value = field.getInitialValue();
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
@ -278,23 +277,16 @@ public class Renderer implements RenderingManager {
|
||||||
value = null;
|
value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasLet) {
|
writer.startVariableDeclaration().appendStaticField(fieldRef);
|
||||||
writer.append("let ");
|
|
||||||
hasLet = true;
|
|
||||||
} else {
|
|
||||||
writer.append(",").ws();
|
|
||||||
}
|
|
||||||
writer.appendStaticField(fieldRef).ws().append("=").ws();
|
|
||||||
context.constantToString(writer, value);
|
context.constantToString(writer, value);
|
||||||
}
|
writer.endDeclaration();
|
||||||
if (hasLet) {
|
|
||||||
writer.append(";").newLine();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderFullClassFunctionDeclaration(ClassReader cls, List<FieldHolder> nonStaticFields) {
|
private void renderFullClassFunctionDeclaration(ClassReader cls, List<FieldHolder> nonStaticFields) {
|
||||||
boolean thisAliased = false;
|
boolean thisAliased = false;
|
||||||
writer.append("function ").appendClass(cls.getName()).append("()").ws().append("{").indent().softNewLine();
|
writer.startFunctionDeclaration().appendClass(cls.getName()).append("()").ws().append("{")
|
||||||
|
.indent().softNewLine();
|
||||||
if (nonStaticFields.size() > 1) {
|
if (nonStaticFields.size() > 1) {
|
||||||
thisAliased = true;
|
thisAliased = true;
|
||||||
writer.append("let a").ws().append("=").ws().append("this;").ws();
|
writer.append("let a").ws().append("=").ws().append("this;").ws();
|
||||||
|
@ -321,18 +313,18 @@ public class Renderer implements RenderingManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.outdent().append("}");
|
writer.outdent().append("}");
|
||||||
writer.newLine();
|
writer.endDeclaration();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderShortClassFunctionDeclaration(ClassReader cls) {
|
private void renderShortClassFunctionDeclaration(ClassReader cls) {
|
||||||
writer.append("let ").appendClass(cls.getName()).ws().append("=").ws()
|
writer.startVariableDeclaration().appendClass(cls.getName())
|
||||||
.appendFunction("$rt_classWithoutFields").append("(");
|
.appendFunction("$rt_classWithoutFields").append("(");
|
||||||
if (cls.hasModifier(ElementModifier.INTERFACE)) {
|
if (cls.hasModifier(ElementModifier.INTERFACE)) {
|
||||||
writer.append("0");
|
writer.append("0");
|
||||||
} else if (!cls.getParent().equals("java.lang.Object")) {
|
} else if (!cls.getParent().equals("java.lang.Object")) {
|
||||||
writer.appendClass(cls.getParent());
|
writer.appendClass(cls.getParent());
|
||||||
}
|
}
|
||||||
writer.append(");").newLine();
|
writer.append(")").endDeclaration();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderMethodBodies(ClassHolder cls, Decompiler decompiler) {
|
private void renderMethodBodies(ClassHolder cls, Decompiler decompiler) {
|
||||||
|
@ -346,27 +338,19 @@ public class Renderer implements RenderingManager {
|
||||||
|
|
||||||
var needsInitializers = !cls.hasModifier(ElementModifier.INTERFACE)
|
var needsInitializers = !cls.hasModifier(ElementModifier.INTERFACE)
|
||||||
&& !cls.hasModifier(ElementModifier.ABSTRACT);
|
&& !cls.hasModifier(ElementModifier.ABSTRACT);
|
||||||
var hasLet = false;
|
|
||||||
for (var method : cls.getMethods()) {
|
for (var method : cls.getMethods()) {
|
||||||
if (!filterMethod(method)) {
|
if (!filterMethod(method)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!hasLet) {
|
writer.startVariableDeclaration();
|
||||||
writer.append("let ");
|
|
||||||
hasLet = true;
|
|
||||||
} else {
|
|
||||||
writer.append(",").newLine();
|
|
||||||
}
|
|
||||||
renderBody(method, decompiler);
|
renderBody(method, decompiler);
|
||||||
|
writer.endDeclaration();
|
||||||
if (needsInitializers && !method.hasModifier(ElementModifier.STATIC)
|
if (needsInitializers && !method.hasModifier(ElementModifier.STATIC)
|
||||||
&& method.getName().equals("<init>")) {
|
&& method.getName().equals("<init>")) {
|
||||||
writer.append(",").newLine();
|
|
||||||
renderInitializer(method);
|
renderInitializer(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasLet) {
|
|
||||||
writer.append(";").newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.emitClass(null);
|
writer.emitClass(null);
|
||||||
}
|
}
|
||||||
|
@ -390,11 +374,10 @@ public class Renderer implements RenderingManager {
|
||||||
|
|
||||||
var clinitCalledField = new FieldReference(cls.getName(), "$_teavm_clinitCalled_$");
|
var clinitCalledField = new FieldReference(cls.getName(), "$_teavm_clinitCalled_$");
|
||||||
if (isAsync) {
|
if (isAsync) {
|
||||||
writer.append("let ").appendStaticField(clinitCalledField).ws().append("=").ws().append("false;")
|
writer.startVariableDeclaration().appendStaticField(clinitCalledField).append("false").endDeclaration();
|
||||||
.softNewLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.append("let ").appendClassInit(cls.getName()).ws().append("=").ws();
|
writer.startVariableDeclaration().appendClassInit(cls.getName());
|
||||||
writer.append("()").sameLineWs().append("=>").ws().append("{").softNewLine().indent();
|
writer.append("()").sameLineWs().append("=>").ws().append("{").softNewLine().indent();
|
||||||
|
|
||||||
if (isAsync) {
|
if (isAsync) {
|
||||||
|
@ -423,7 +406,7 @@ public class Renderer implements RenderingManager {
|
||||||
writer.outdent().append("case 1:").indent().softNewLine();
|
writer.outdent().append("case 1:").indent().softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.appendMethodBody(new MethodReference(cls.getName(), clinit.getDescriptor()))
|
writer.appendMethod(new MethodReference(cls.getName(), clinit.getDescriptor()))
|
||||||
.append("();").softNewLine();
|
.append("();").softNewLine();
|
||||||
|
|
||||||
if (isAsync) {
|
if (isAsync) {
|
||||||
|
@ -438,8 +421,7 @@ public class Renderer implements RenderingManager {
|
||||||
writer.appendFunction("$rt_nativeThread").append("().push(" + context.pointerName() + ");").softNewLine();
|
writer.appendFunction("$rt_nativeThread").append("().push(" + context.pointerName() + ");").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.outdent().append("};");
|
writer.outdent().append("}").endDeclaration();
|
||||||
writer.newLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderEraseClinit(ClassReader cls) {
|
private void renderEraseClinit(ClassReader cls) {
|
||||||
|
@ -696,7 +678,7 @@ public class Renderer implements RenderingManager {
|
||||||
private void renderInitializer(MethodReader method) {
|
private void renderInitializer(MethodReader method) {
|
||||||
MethodReference ref = method.getReference();
|
MethodReference ref = method.getReference();
|
||||||
writer.emitMethod(ref.getDescriptor());
|
writer.emitMethod(ref.getDescriptor());
|
||||||
writer.appendInit(ref).ws().append("=").ws();
|
writer.startVariableDeclaration().appendInit(ref);
|
||||||
if (ref.parameterCount() != 1) {
|
if (ref.parameterCount() != 1) {
|
||||||
writer.append("(");
|
writer.append("(");
|
||||||
}
|
}
|
||||||
|
@ -714,14 +696,14 @@ public class Renderer implements RenderingManager {
|
||||||
String instanceName = variableNameForInitializer(ref.parameterCount());
|
String instanceName = variableNameForInitializer(ref.parameterCount());
|
||||||
writer.append("let " + instanceName).ws().append("=").ws().append("new ").appendClass(
|
writer.append("let " + instanceName).ws().append("=").ws().append("new ").appendClass(
|
||||||
ref.getClassName()).append("();").softNewLine();
|
ref.getClassName()).append("();").softNewLine();
|
||||||
writer.appendMethodBody(ref).append("(" + instanceName);
|
writer.appendMethod(ref).append("(" + instanceName);
|
||||||
for (int i = 0; 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 " + instanceName + ";").softNewLine();
|
writer.append("return " + instanceName + ";").softNewLine();
|
||||||
writer.outdent().append("}");
|
writer.outdent().append("}").endDeclaration();
|
||||||
writer.emitMethod(null);
|
writer.emitMethod(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,7 +735,7 @@ public class Renderer implements RenderingManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void emitVirtualDeclaration(MethodReference ref) {
|
private void emitVirtualDeclaration(MethodReference ref) {
|
||||||
String methodName = context.getNaming().getNameFor(ref.getDescriptor());
|
String methodName = context.getNaming().instanceMethodName(ref.getDescriptor());
|
||||||
writer.append("\"").append(methodName).append("\"");
|
writer.append("\"").append(methodName).append("\"");
|
||||||
writer.append(",").ws();
|
writer.append(",").ws();
|
||||||
emitVirtualFunctionWrapper(ref);
|
emitVirtualFunctionWrapper(ref);
|
||||||
|
@ -762,7 +744,7 @@ public class Renderer implements RenderingManager {
|
||||||
private void emitVirtualFunctionWrapper(MethodReference method) {
|
private void emitVirtualFunctionWrapper(MethodReference method) {
|
||||||
if (method.parameterCount() <= 4) {
|
if (method.parameterCount() <= 4) {
|
||||||
writer.appendFunction("$rt_wrapFunction" + method.parameterCount());
|
writer.appendFunction("$rt_wrapFunction" + method.parameterCount());
|
||||||
writer.append("(").appendMethodBody(method).append(")");
|
writer.append("(").appendMethod(method).append(")");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +763,7 @@ public class Renderer implements RenderingManager {
|
||||||
if (method.getDescriptor().getResultType() != ValueType.VOID) {
|
if (method.getDescriptor().getResultType() != ValueType.VOID) {
|
||||||
writer.append("return ");
|
writer.append("return ");
|
||||||
}
|
}
|
||||||
writer.appendMethodBody(method).append("(");
|
writer.appendMethod(method).append("(");
|
||||||
writer.append("this");
|
writer.append("this");
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
writer.append(",").ws().append(arg);
|
writer.append(",").ws().append(arg);
|
||||||
|
@ -793,7 +775,7 @@ public class Renderer implements RenderingManager {
|
||||||
MethodReference ref = method.getReference();
|
MethodReference ref = method.getReference();
|
||||||
writer.emitMethod(ref.getDescriptor());
|
writer.emitMethod(ref.getDescriptor());
|
||||||
|
|
||||||
writer.appendMethodBody(ref).ws().append("=").ws();
|
writer.appendMethod(ref);
|
||||||
if (method.hasModifier(ElementModifier.NATIVE)) {
|
if (method.hasModifier(ElementModifier.NATIVE)) {
|
||||||
renderNativeBody(method, classSource);
|
renderNativeBody(method, classSource);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,7 +28,6 @@ import org.mozilla.javascript.ast.AstRoot;
|
||||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||||
import org.teavm.backend.javascript.codegen.SourceWriterSink;
|
import org.teavm.backend.javascript.codegen.SourceWriterSink;
|
||||||
import org.teavm.backend.javascript.templating.AstRemoval;
|
import org.teavm.backend.javascript.templating.AstRemoval;
|
||||||
import org.teavm.backend.javascript.templating.LetJoiner;
|
|
||||||
import org.teavm.backend.javascript.templating.RemovablePartsFinder;
|
import org.teavm.backend.javascript.templating.RemovablePartsFinder;
|
||||||
import org.teavm.backend.javascript.templating.TemplatingAstTransformer;
|
import org.teavm.backend.javascript.templating.TemplatingAstTransformer;
|
||||||
import org.teavm.backend.javascript.templating.TemplatingAstWriter;
|
import org.teavm.backend.javascript.templating.TemplatingAstWriter;
|
||||||
|
@ -69,13 +68,13 @@ public class RuntimeRenderer {
|
||||||
|
|
||||||
public void renderRuntime() {
|
public void renderRuntime() {
|
||||||
for (var ast : runtimeAstParts) {
|
for (var ast : runtimeAstParts) {
|
||||||
renderHandWrittenRuntime(ast);
|
renderRuntimePart(ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderEpilogue() {
|
public void renderEpilogue() {
|
||||||
for (var ast : epilogueAstParts) {
|
for (var ast : epilogueAstParts) {
|
||||||
renderHandWrittenRuntime(ast);
|
renderRuntimePart(ast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +86,7 @@ public class RuntimeRenderer {
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderHandWrittenRuntime(AstRoot ast) {
|
private void renderRuntimePart(AstRoot ast) {
|
||||||
var astWriter = new TemplatingAstWriter(writer, null, null, classInitializerInfo);
|
var astWriter = new TemplatingAstWriter(writer, null, null, classInitializerInfo);
|
||||||
astWriter.hoist(ast);
|
astWriter.hoist(ast);
|
||||||
astWriter.print(ast);
|
astWriter.print(ast);
|
||||||
|
@ -118,14 +117,11 @@ public class RuntimeRenderer {
|
||||||
|
|
||||||
public void removeUnusedParts() {
|
public void removeUnusedParts() {
|
||||||
var removal = new AstRemoval(removablePartsFinder.getAllRemovableParts());
|
var removal = new AstRemoval(removablePartsFinder.getAllRemovableParts());
|
||||||
var letJoiner = new LetJoiner();
|
|
||||||
for (var part : runtimeAstParts) {
|
for (var part : runtimeAstParts) {
|
||||||
removal.visit(part);
|
removal.visit(part);
|
||||||
letJoiner.visit(part);
|
|
||||||
}
|
}
|
||||||
for (var part : epilogueAstParts) {
|
for (var part : epilogueAstParts) {
|
||||||
removal.visit(part);
|
removal.visit(part);
|
||||||
letJoiner.visit(part);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1100,10 +1100,10 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
expr.getArguments().get(0).acceptVisitor(this);
|
||||||
}
|
}
|
||||||
MethodReference method = expr.getMethod();
|
MethodReference method = expr.getMethod();
|
||||||
String name = naming.getNameFor(method.getDescriptor());
|
String name = naming.instanceMethodName(method.getDescriptor());
|
||||||
switch (expr.getType()) {
|
switch (expr.getType()) {
|
||||||
case STATIC:
|
case STATIC:
|
||||||
writer.appendMethodBody(method).append("(");
|
writer.appendMethod(method).append("(");
|
||||||
for (int i = 0; i < expr.getArguments().size(); ++i) {
|
for (int i = 0; i < expr.getArguments().size(); ++i) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
writer.append(",").ws();
|
writer.append(",").ws();
|
||||||
|
@ -1113,7 +1113,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPECIAL:
|
case SPECIAL:
|
||||||
writer.appendMethodBody(method).append("(");
|
writer.appendMethod(method).append("(");
|
||||||
precedence = Precedence.min();
|
precedence = Precedence.min();
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
expr.getArguments().get(0).acceptVisitor(this);
|
||||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||||
|
@ -1507,13 +1507,13 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorEnterStatement statement) {
|
public void visit(MonitorEnterStatement statement) {
|
||||||
if (async) {
|
if (async) {
|
||||||
writer.appendMethodBody(NameFrequencyEstimator.MONITOR_ENTER_METHOD).append("(");
|
writer.appendMethod(NameFrequencyEstimator.MONITOR_ENTER_METHOD).append("(");
|
||||||
precedence = Precedence.min();
|
precedence = Precedence.min();
|
||||||
statement.getObjectRef().acceptVisitor(this);
|
statement.getObjectRef().acceptVisitor(this);
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
emitSuspendChecker();
|
emitSuspendChecker();
|
||||||
} else {
|
} else {
|
||||||
writer.appendMethodBody(NameFrequencyEstimator.MONITOR_ENTER_SYNC_METHOD).append('(');
|
writer.appendMethod(NameFrequencyEstimator.MONITOR_ENTER_SYNC_METHOD).append('(');
|
||||||
precedence = Precedence.min();
|
precedence = Precedence.min();
|
||||||
statement.getObjectRef().acceptVisitor(this);
|
statement.getObjectRef().acceptVisitor(this);
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
|
@ -1530,12 +1530,12 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorExitStatement statement) {
|
public void visit(MonitorExitStatement statement) {
|
||||||
if (async) {
|
if (async) {
|
||||||
writer.appendMethodBody(NameFrequencyEstimator.MONITOR_EXIT_METHOD).append("(");
|
writer.appendMethod(NameFrequencyEstimator.MONITOR_EXIT_METHOD).append("(");
|
||||||
precedence = Precedence.min();
|
precedence = Precedence.min();
|
||||||
statement.getObjectRef().acceptVisitor(this);
|
statement.getObjectRef().acceptVisitor(this);
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
} else {
|
} else {
|
||||||
writer.appendMethodBody(NameFrequencyEstimator.MONITOR_EXIT_SYNC_METHOD).append('(');
|
writer.appendMethod(NameFrequencyEstimator.MONITOR_EXIT_SYNC_METHOD).append('(');
|
||||||
precedence = Precedence.min();
|
precedence = Precedence.min();
|
||||||
statement.getObjectRef().acceptVisitor(this);
|
statement.getObjectRef().acceptVisitor(this);
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023 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.templating;
|
|
||||||
|
|
||||||
import org.mozilla.javascript.ast.AstNode;
|
|
||||||
import org.mozilla.javascript.ast.AstRoot;
|
|
||||||
import org.mozilla.javascript.ast.Block;
|
|
||||||
import org.mozilla.javascript.ast.FunctionNode;
|
|
||||||
import org.mozilla.javascript.ast.Scope;
|
|
||||||
import org.mozilla.javascript.ast.VariableDeclaration;
|
|
||||||
import org.teavm.backend.javascript.ast.AstVisitor;
|
|
||||||
|
|
||||||
public class LetJoiner extends AstVisitor {
|
|
||||||
@Override
|
|
||||||
public void visit(Block node) {
|
|
||||||
visitMany(node);
|
|
||||||
super.visit(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Scope node) {
|
|
||||||
visitMany(node);
|
|
||||||
super.visit(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(AstRoot node) {
|
|
||||||
visitMany(node);
|
|
||||||
super.visit(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(FunctionNode node) {
|
|
||||||
visitMany(node.getBody());
|
|
||||||
super.visit(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void visitMany(AstNode node) {
|
|
||||||
VariableDeclaration previous = null;
|
|
||||||
for (var childNode = node.getFirstChild(); childNode != null;) {
|
|
||||||
var nextNode = childNode.getNext();
|
|
||||||
var child = (AstNode) childNode;
|
|
||||||
if (child instanceof VariableDeclaration) {
|
|
||||||
var decl = (VariableDeclaration) childNode;
|
|
||||||
if (previous != null && previous.getType() == decl.getType()) {
|
|
||||||
previous.getVariables().addAll(decl.getVariables());
|
|
||||||
node.removeChild(decl);
|
|
||||||
} else {
|
|
||||||
previous = decl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
previous = null;
|
|
||||||
}
|
|
||||||
childNode = nextNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,9 +16,7 @@
|
||||||
package org.teavm.backend.javascript.templating;
|
package org.teavm.backend.javascript.templating;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import org.mozilla.javascript.ast.ElementGet;
|
import org.mozilla.javascript.ast.ElementGet;
|
||||||
import org.mozilla.javascript.ast.FunctionCall;
|
import org.mozilla.javascript.ast.FunctionCall;
|
||||||
import org.mozilla.javascript.ast.FunctionNode;
|
import org.mozilla.javascript.ast.FunctionNode;
|
||||||
|
@ -39,8 +37,6 @@ public class TemplatingAstWriter extends AstWriter {
|
||||||
private Scope scope;
|
private Scope scope;
|
||||||
private Map<String, SourceFragment> fragments = new HashMap<>();
|
private Map<String, SourceFragment> fragments = new HashMap<>();
|
||||||
private ClassInitializerInfo classInitializerInfo;
|
private ClassInitializerInfo classInitializerInfo;
|
||||||
private Set<Scope> topLevelScopes = new HashSet<>();
|
|
||||||
private boolean inFunction;
|
|
||||||
|
|
||||||
public TemplatingAstWriter(SourceWriter writer, Map<String, SourceFragment> names, Scope scope,
|
public TemplatingAstWriter(SourceWriter writer, Map<String, SourceFragment> names, Scope scope,
|
||||||
ClassInitializerInfo classInitializerInfo) {
|
ClassInitializerInfo classInitializerInfo) {
|
||||||
|
@ -113,7 +109,7 @@ public class TemplatingAstWriter extends AstWriter {
|
||||||
}
|
}
|
||||||
var method = new MethodReference(((StringLiteral) classArg).getValue(),
|
var method = new MethodReference(((StringLiteral) classArg).getValue(),
|
||||||
MethodDescriptor.parse(((StringLiteral) methodArg).getValue()));
|
MethodDescriptor.parse(((StringLiteral) methodArg).getValue()));
|
||||||
writer.appendMethodBody(method);
|
writer.appendMethod(method);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +206,7 @@ public class TemplatingAstWriter extends AstWriter {
|
||||||
}
|
}
|
||||||
var method = MethodDescriptor.parse(((StringLiteral) arg).getValue());
|
var method = MethodDescriptor.parse(((StringLiteral) arg).getValue());
|
||||||
print(get.getTarget());
|
print(get.getTarget());
|
||||||
writer.append('.').appendMethod(method);
|
writer.append('.').appendVirtualMethod(method);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,27 +246,7 @@ public class TemplatingAstWriter extends AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void print(FunctionNode node) {
|
protected boolean isTopLevel() {
|
||||||
if (inFunction) {
|
return names == null;
|
||||||
super.print(node);
|
|
||||||
} else {
|
|
||||||
inFunction = true;
|
|
||||||
super.print(node);
|
|
||||||
inFunction = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onEnterScope(Scope scope) {
|
|
||||||
if (names == null && !inFunction) {
|
|
||||||
topLevelScopes.add(scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onLeaveScope(Scope scope) {
|
|
||||||
if (names == null && !inFunction) {
|
|
||||||
topLevelScopes.remove(scope);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,8 @@ class JSAliasRenderer implements RendererListener, VirtualMethodContributor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.append("let ").appendFunction("$rt_jso_marker").ws().append("=").ws()
|
writer.startVariableDeclaration().appendFunction("$rt_jso_marker")
|
||||||
.appendGlobal("Symbol").append("('jsoClass');").newLine();
|
.appendGlobal("Symbol").append("('jsoClass')").endDeclaration();
|
||||||
writer.append("(function()").ws().append("{").softNewLine().indent();
|
writer.append("(function()").ws().append("{").softNewLine().indent();
|
||||||
writer.append("var c;").softNewLine();
|
writer.append("var c;").softNewLine();
|
||||||
for (String className : classSource.getClassNames()) {
|
for (String className : classSource.getClassNames()) {
|
||||||
|
@ -100,7 +100,7 @@ class JSAliasRenderer implements RendererListener, VirtualMethodContributor {
|
||||||
} else {
|
} else {
|
||||||
writer.append("c.").append(aliasEntry.getKey());
|
writer.append("c.").append(aliasEntry.getKey());
|
||||||
}
|
}
|
||||||
writer.ws().append("=").ws().append("c.").appendMethod(aliasEntry.getValue())
|
writer.ws().append("=").ws().append("c.").appendVirtualMethod(aliasEntry.getValue())
|
||||||
.append(";").softNewLine();
|
.append(";").softNewLine();
|
||||||
}
|
}
|
||||||
for (var aliasEntry : properties.entrySet()) {
|
for (var aliasEntry : properties.entrySet()) {
|
||||||
|
@ -111,10 +111,10 @@ class JSAliasRenderer implements RendererListener, VirtualMethodContributor {
|
||||||
writer.append("Object.defineProperty(c,")
|
writer.append("Object.defineProperty(c,")
|
||||||
.ws().append("\"").append(aliasEntry.getKey()).append("\",")
|
.ws().append("\"").append(aliasEntry.getKey()).append("\",")
|
||||||
.ws().append("{").indent().softNewLine();
|
.ws().append("{").indent().softNewLine();
|
||||||
writer.append("get:").ws().append("c.").appendMethod(propInfo.getter);
|
writer.append("get:").ws().append("c.").appendVirtualMethod(propInfo.getter);
|
||||||
if (propInfo.setter != null && classReader.getMethod(propInfo.setter) != null) {
|
if (propInfo.setter != null && classReader.getMethod(propInfo.setter) != null) {
|
||||||
writer.append(",").softNewLine();
|
writer.append(",").softNewLine();
|
||||||
writer.append("set:").ws().append("c.").appendMethod(propInfo.setter);
|
writer.append("set:").ws().append("c.").appendVirtualMethod(propInfo.setter);
|
||||||
}
|
}
|
||||||
writer.softNewLine().outdent().append("});").softNewLine();
|
writer.softNewLine().outdent().append("});").softNewLine();
|
||||||
}
|
}
|
||||||
|
@ -198,7 +198,7 @@ class JSAliasRenderer implements RendererListener, VirtualMethodContributor {
|
||||||
writer.append("this.").appendField(functorField).ws().append('=').ws().append("function(");
|
writer.append("this.").appendField(functorField).ws().append('=').ws().append("function(");
|
||||||
appendArguments(functorMethod.parameterCount());
|
appendArguments(functorMethod.parameterCount());
|
||||||
writer.append(")").ws().append('{').indent().softNewLine();
|
writer.append(")").ws().append('{').indent().softNewLine();
|
||||||
writer.append("return self.").appendMethod(functorMethod).append('(');
|
writer.append("return self.").appendVirtualMethod(functorMethod).append('(');
|
||||||
appendArguments(functorMethod.parameterCount());
|
appendArguments(functorMethod.parameterCount());
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
writer.outdent().append("};").softNewLine();
|
writer.outdent().append("};").softNewLine();
|
||||||
|
|
|
@ -69,8 +69,8 @@ class JSBodyBloatedEmitter implements JSBodyEmitter {
|
||||||
private void emit(SourceWriter writer, EmissionStrategy strategy) {
|
private void emit(SourceWriter writer, EmissionStrategy strategy) {
|
||||||
int bodyParamCount = isStatic ? method.parameterCount() : method.parameterCount() - 1;
|
int bodyParamCount = isStatic ? method.parameterCount() : method.parameterCount() - 1;
|
||||||
|
|
||||||
writer.append("if (!").appendMethodBody(method).append(".$native)").ws().append('{').indent().newLine();
|
writer.append("if (!").appendMethod(method).append(".$native)").ws().append('{').indent().newLine();
|
||||||
writer.appendMethodBody(method).append(".$native").ws().append('=').ws().append("function(");
|
writer.appendMethod(method).append(".$native").ws().append('=').ws().append("function(");
|
||||||
int count = method.parameterCount();
|
int count = method.parameterCount();
|
||||||
|
|
||||||
var first = true;
|
var first = true;
|
||||||
|
@ -135,11 +135,11 @@ class JSBodyBloatedEmitter implements JSBodyEmitter {
|
||||||
|
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
writer.outdent().append("};").softNewLine();
|
writer.outdent().append("};").softNewLine();
|
||||||
writer.appendMethodBody(method).ws().append('=').ws().appendMethodBody(method).append(".$native;")
|
writer.appendMethod(method).ws().append('=').ws().appendMethod(method).append(".$native;")
|
||||||
.softNewLine();
|
.softNewLine();
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
|
|
||||||
writer.append("return ").appendMethodBody(method).append('(');
|
writer.append("return ").appendMethod(method).append('(');
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
writer.append(',').ws();
|
writer.append(',').ws();
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin, Virtua
|
||||||
template.builder("asyncMethod")
|
template.builder("asyncMethod")
|
||||||
.withContext(context)
|
.withContext(context)
|
||||||
.withFragment("callMethod", (w, p) -> {
|
.withFragment("callMethod", (w, p) -> {
|
||||||
w.appendMethodBody(asyncRef).append('(');
|
w.appendMethod(asyncRef).append('(');
|
||||||
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
|
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
|
||||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||||
int start = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
|
int start = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
|
||||||
|
|
|
@ -132,7 +132,7 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
||||||
MethodReader method = cls.getMethod(new MethodDescriptor("<init>", void.class));
|
MethodReader method = cls.getMethod(new MethodDescriptor("<init>", void.class));
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
writer.appendClass(clsName).append("[c]").ws().append("=").ws()
|
writer.appendClass(clsName).append("[c]").ws().append("=").ws()
|
||||||
.appendMethodBody(method.getReference()).append(";").softNewLine();
|
.appendMethod(method.getReference()).append(";").softNewLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,14 +159,14 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
||||||
ValueType.arrayOf(ValueType.object(clsName))));
|
ValueType.arrayOf(ValueType.object(clsName))));
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
writer.appendClass(clsName).append("[c]").ws().append("=").ws();
|
writer.appendClass(clsName).append("[c]").ws().append("=").ws();
|
||||||
writer.appendMethodBody(method.getReference());
|
writer.appendMethod(method.getReference());
|
||||||
writer.append(";").softNewLine();
|
writer.append(";").softNewLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodReference selfRef = new MethodReference(Platform.class, "getEnumConstants",
|
MethodReference selfRef = new MethodReference(Platform.class, "getEnumConstants",
|
||||||
PlatformClass.class, Enum[].class);
|
PlatformClass.class, Enum[].class);
|
||||||
writer.appendMethodBody(selfRef).ws().append("=").ws().append("cls").sameLineWs().append("=>").ws()
|
writer.appendMethod(selfRef).ws().append("=").ws().append("cls").sameLineWs().append("=>").ws()
|
||||||
.append("{").softNewLine().indent();
|
.append("{").softNewLine().indent();
|
||||||
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
|
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
|
||||||
writer.append("return null;").softNewLine();
|
writer.append("return null;").softNewLine();
|
||||||
|
@ -178,7 +178,7 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
||||||
writer.append("return cls[c];").softNewLine();
|
writer.append("return cls[c];").softNewLine();
|
||||||
writer.outdent().append("};").softNewLine();
|
writer.outdent().append("};").softNewLine();
|
||||||
|
|
||||||
writer.append("return ").appendMethodBody(selfRef).append("(").append(context.getParameterName(1))
|
writer.append("return ").appendMethod(selfRef).append("(").append(context.getParameterName(1))
|
||||||
.append(");").softNewLine();
|
.append(");").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,15 +196,16 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
||||||
|
|
||||||
MethodReference selfRef = new MethodReference(Platform.class, "getAnnotations", PlatformClass.class,
|
MethodReference selfRef = new MethodReference(Platform.class, "getAnnotations", PlatformClass.class,
|
||||||
Annotation[].class);
|
Annotation[].class);
|
||||||
writer.appendMethodBody(selfRef).ws().append("=").ws().append("cls").sameLineWs().append("=>").ws()
|
writer.appendMethod(selfRef).ws().append("=").ws().append("cls").sameLineWs().append("=>").ws()
|
||||||
.append("{").softNewLine().indent();
|
.append("{").softNewLine().indent();
|
||||||
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
|
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
|
||||||
writer.append("return null;").softNewLine();
|
writer.append("return null;").softNewLine();
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
writer.append("return cls[c].").appendMethod("getAnnotations", Annotation[].class).append("();").softNewLine();
|
writer.append("return cls[c].").appendVirtualMethod("getAnnotations", Annotation[].class).append("();")
|
||||||
|
.softNewLine();
|
||||||
writer.outdent().append("};").softNewLine();
|
writer.outdent().append("};").softNewLine();
|
||||||
|
|
||||||
writer.append("return ").appendMethodBody(selfRef).append("(").append(context.getParameterName(1))
|
writer.append("return ").appendMethod(selfRef).append("(").append(context.getParameterName(1))
|
||||||
.append(");").softNewLine();
|
.append(");").softNewLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,6 +241,15 @@ public final class TeaVMRunner {
|
||||||
tool.setObfuscated(commandLine.hasOption("m"));
|
tool.setObfuscated(commandLine.hasOption("m"));
|
||||||
tool.setStrict(commandLine.hasOption("strict"));
|
tool.setStrict(commandLine.hasOption("strict"));
|
||||||
parseJsModuleOption();
|
parseJsModuleOption();
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseJsModuleOption() {
|
private void parseJsModuleOption() {
|
||||||
|
|
|
@ -78,6 +78,7 @@ public class TeaVMTool {
|
||||||
private boolean obfuscated = true;
|
private boolean obfuscated = true;
|
||||||
private JSModuleType jsModuleType = JSModuleType.UMD;
|
private JSModuleType jsModuleType = JSModuleType.UMD;
|
||||||
private boolean strict;
|
private boolean strict;
|
||||||
|
private int maxTopLevelNames = 80_000;
|
||||||
private String mainClass;
|
private String mainClass;
|
||||||
private String entryPointName = "main";
|
private String entryPointName = "main";
|
||||||
private Properties properties = new Properties();
|
private Properties properties = new Properties();
|
||||||
|
@ -139,6 +140,10 @@ public class TeaVMTool {
|
||||||
this.strict = strict;
|
this.strict = strict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxTopLevelNames(int maxTopLevelNames) {
|
||||||
|
this.maxTopLevelNames = maxTopLevelNames;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isIncremental() {
|
public boolean isIncremental() {
|
||||||
return incremental;
|
return incremental;
|
||||||
}
|
}
|
||||||
|
@ -336,6 +341,7 @@ public class TeaVMTool {
|
||||||
javaScriptTarget = new JavaScriptTarget();
|
javaScriptTarget = new JavaScriptTarget();
|
||||||
javaScriptTarget.setObfuscated(obfuscated);
|
javaScriptTarget.setObfuscated(obfuscated);
|
||||||
javaScriptTarget.setStrict(strict);
|
javaScriptTarget.setStrict(strict);
|
||||||
|
javaScriptTarget.setMaxTopLevelNames(maxTopLevelNames);
|
||||||
|
|
||||||
debugEmitter = debugInformationGenerated || sourceMapsFileGenerated
|
debugEmitter = debugInformationGenerated || sourceMapsFileGenerated
|
||||||
? new DebugInformationBuilder(referenceCache) : null;
|
? new DebugInformationBuilder(referenceCache) : null;
|
||||||
|
|
|
@ -63,6 +63,8 @@ public interface BuildStrategy {
|
||||||
|
|
||||||
void setJsModuleType(JSModuleType jsModuleType);
|
void setJsModuleType(JSModuleType jsModuleType);
|
||||||
|
|
||||||
|
void setMaxTopLevelNames(int maxTopLevelNames);
|
||||||
|
|
||||||
void setProperties(Properties properties);
|
void setProperties(Properties properties);
|
||||||
|
|
||||||
void setTransformers(String[] transformers);
|
void setTransformers(String[] transformers);
|
||||||
|
|
|
@ -56,6 +56,7 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
||||||
private boolean obfuscated;
|
private boolean obfuscated;
|
||||||
private JSModuleType jsModuleType;
|
private JSModuleType jsModuleType;
|
||||||
private boolean strict;
|
private boolean strict;
|
||||||
|
private int maxTopLevelNames = 80_000;
|
||||||
private boolean sourceMapsFileGenerated;
|
private boolean sourceMapsFileGenerated;
|
||||||
private boolean debugInformationGenerated;
|
private boolean debugInformationGenerated;
|
||||||
private TeaVMSourceFilePolicy sourceMapsSourcePolicy;
|
private TeaVMSourceFilePolicy sourceMapsSourcePolicy;
|
||||||
|
@ -174,6 +175,11 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
||||||
this.jsModuleType = jsModuleType;
|
this.jsModuleType = jsModuleType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaxTopLevelNames(int maxTopLevelNames) {
|
||||||
|
this.maxTopLevelNames = maxTopLevelNames;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTransformers(String[] transformers) {
|
public void setTransformers(String[] transformers) {
|
||||||
this.transformers = transformers.clone();
|
this.transformers = transformers.clone();
|
||||||
|
@ -256,6 +262,7 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
||||||
tool.setObfuscated(obfuscated);
|
tool.setObfuscated(obfuscated);
|
||||||
tool.setJsModuleType(jsModuleType);
|
tool.setJsModuleType(jsModuleType);
|
||||||
tool.setStrict(strict);
|
tool.setStrict(strict);
|
||||||
|
tool.setMaxTopLevelNames(maxTopLevelNames);
|
||||||
tool.setIncremental(incremental);
|
tool.setIncremental(incremental);
|
||||||
tool.getTransformers().addAll(Arrays.asList(transformers));
|
tool.getTransformers().addAll(Arrays.asList(transformers));
|
||||||
tool.getClassesToPreserve().addAll(Arrays.asList(classesToPreserve));
|
tool.getClassesToPreserve().addAll(Arrays.asList(classesToPreserve));
|
||||||
|
|
|
@ -148,6 +148,11 @@ public class RemoteBuildStrategy implements BuildStrategy {
|
||||||
request.jsModuleType = jsModuleType;
|
request.jsModuleType = jsModuleType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaxTopLevelNames(int maxTopLevelNames) {
|
||||||
|
request.maxTopLevelNames = maxTopLevelNames;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTransformers(String[] transformers) {
|
public void setTransformers(String[] transformers) {
|
||||||
request.transformers = transformers.clone();
|
request.transformers = transformers.clone();
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class RemoteBuildRequest implements Serializable {
|
||||||
public boolean obfuscated;
|
public boolean obfuscated;
|
||||||
public boolean strict;
|
public boolean strict;
|
||||||
public JSModuleType jsModuleType;
|
public JSModuleType jsModuleType;
|
||||||
|
public int maxTopLevelNames = 80_000;
|
||||||
public Properties properties;
|
public Properties properties;
|
||||||
public TeaVMOptimizationLevel optimizationLevel;
|
public TeaVMOptimizationLevel optimizationLevel;
|
||||||
public boolean fastDependencyAnalysis;
|
public boolean fastDependencyAnalysis;
|
||||||
|
|
|
@ -123,6 +123,7 @@ public class TeaVMPlugin implements Plugin<Project> {
|
||||||
task.getStrict().convention(js.getStrict());
|
task.getStrict().convention(js.getStrict());
|
||||||
task.getEntryPointName().convention(js.getEntryPointName());
|
task.getEntryPointName().convention(js.getEntryPointName());
|
||||||
task.getSourceFilePolicy().convention(js.getSourceFilePolicy());
|
task.getSourceFilePolicy().convention(js.getSourceFilePolicy());
|
||||||
|
task.getMaxTopLevelNames().convention(js.getMaxTopLevelNames());
|
||||||
|
|
||||||
task.getSourceFiles().from(project.provider(() -> {
|
task.getSourceFiles().from(project.provider(() -> {
|
||||||
var result = new ArrayList<File>();
|
var result = new ArrayList<File>();
|
||||||
|
|
|
@ -31,4 +31,6 @@ public interface TeaVMJSConfiguration extends TeaVMWebConfiguration {
|
||||||
Property<String> getTargetFileName();
|
Property<String> getTargetFileName();
|
||||||
|
|
||||||
Property<SourceFilePolicy> getSourceFilePolicy();
|
Property<SourceFilePolicy> getSourceFilePolicy();
|
||||||
|
|
||||||
|
Property<Integer> getMaxTopLevelNames();
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,11 +63,18 @@ public abstract class GenerateJavaScriptTask extends TeaVMTask {
|
||||||
@Optional
|
@Optional
|
||||||
public abstract Property<SourceFilePolicy> getSourceFilePolicy();
|
public abstract Property<SourceFilePolicy> getSourceFilePolicy();
|
||||||
|
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
public abstract Property<Integer> getMaxTopLevelNames();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setupBuilder(BuildStrategy builder) {
|
protected void setupBuilder(BuildStrategy builder) {
|
||||||
builder.setTargetType(TeaVMTargetType.JAVASCRIPT);
|
builder.setTargetType(TeaVMTargetType.JAVASCRIPT);
|
||||||
builder.setObfuscated(getObfuscated().get());
|
builder.setObfuscated(getObfuscated().get());
|
||||||
builder.setStrict(getStrict().get());
|
builder.setStrict(getStrict().get());
|
||||||
|
if (getMaxTopLevelNames().isPresent()) {
|
||||||
|
builder.setMaxTopLevelNames(getMaxTopLevelNames().get());
|
||||||
|
}
|
||||||
switch (getModuleType().get()) {
|
switch (getModuleType().get()) {
|
||||||
case UMD:
|
case UMD:
|
||||||
builder.setJsModuleType(org.teavm.backend.javascript.JSModuleType.UMD);
|
builder.setJsModuleType(org.teavm.backend.javascript.JSModuleType.UMD);
|
||||||
|
|
|
@ -65,7 +65,7 @@ class TestExceptionPlugin implements TeaVMPlugin {
|
||||||
writer.appendClass("java.lang.Throwable").append(".prototype.getMessage").ws().append("=").ws()
|
writer.appendClass("java.lang.Throwable").append(".prototype.getMessage").ws().append("=").ws()
|
||||||
.append("function()").ws().append("{").indent().softNewLine();
|
.append("function()").ws().append("{").indent().softNewLine();
|
||||||
writer.append("return ").appendFunction("$rt_ustr").append("(this.")
|
writer.append("return ").appendFunction("$rt_ustr").append("(this.")
|
||||||
.appendMethod("getMessage", String.class).append("());").softNewLine();
|
.appendVirtualMethod("getMessage", String.class).append("());").softNewLine();
|
||||||
writer.outdent().append("};").newLine();
|
writer.outdent().append("};").newLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,9 @@ public class TeaVMCompileMojo extends AbstractMojo {
|
||||||
@Parameter(property = "teavm.jsModuleType", defaultValue = "UMD")
|
@Parameter(property = "teavm.jsModuleType", defaultValue = "UMD")
|
||||||
private JSModuleType jsModuleType;
|
private JSModuleType jsModuleType;
|
||||||
|
|
||||||
|
@Parameter(property = "teavm.maxTopLevelNames", defaultValue = "80000")
|
||||||
|
private int maxTopLevelNames = 80_000;
|
||||||
|
|
||||||
@Parameter
|
@Parameter
|
||||||
private Properties properties;
|
private Properties properties;
|
||||||
|
|
||||||
|
@ -169,6 +172,7 @@ public class TeaVMCompileMojo extends AbstractMojo {
|
||||||
builder.setObfuscated(minifying);
|
builder.setObfuscated(minifying);
|
||||||
builder.setStrict(strict);
|
builder.setStrict(strict);
|
||||||
builder.setJsModuleType(jsModuleType);
|
builder.setJsModuleType(jsModuleType);
|
||||||
|
builder.setMaxTopLevelNames(maxTopLevelNames);
|
||||||
builder.setTargetDirectory(targetDirectory.getAbsolutePath());
|
builder.setTargetDirectory(targetDirectory.getAbsolutePath());
|
||||||
if (transformers != null) {
|
if (transformers != null) {
|
||||||
builder.setTransformers(transformers);
|
builder.setTransformers(transformers);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user