diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index 57827593e..4afc63436 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -55,6 +55,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext private DeferredCallSite lastCallSite; private DeferredCallSite prevCallSite; private Set asyncMethods; + private Set asyncFamilyMethods; private Diagnostics diagnostics; private boolean async; @@ -79,13 +80,15 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader, - ServiceRepository services, Set asyncMethods, Diagnostics diagnostics) { + ServiceRepository services, Set asyncMethods, Set asyncFamilyMethods, + Diagnostics diagnostics) { this.naming = writer.getNaming(); this.writer = writer; this.classSource = classSource; this.classLoader = classLoader; this.services = services; this.asyncMethods = new HashSet<>(asyncMethods); + this.asyncFamilyMethods = new HashSet<>(asyncFamilyMethods); this.diagnostics = diagnostics; } @@ -460,7 +463,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append(");").ws().append("}"); debugEmitter.emitMethod(null); - if (!method.isAsync()) { + if (!method.isAsync() && asyncFamilyMethods.contains(method.getReference())) { writer.append(",").newLine(); writer.append("\"").append(naming.getNameForAsync(ref)).append("\",").ws(); writer.append("$rt_asyncAdapter(").appendMethodBody(ref).append(')'); diff --git a/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java b/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java index 75dbb481b..78f89b64c 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java +++ b/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java @@ -15,8 +15,7 @@ */ package org.teavm.model.util; -import java.util.HashSet; -import java.util.Set; +import java.util.*; import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraphNode; import org.teavm.callgraph.CallSite; @@ -32,6 +31,9 @@ import org.teavm.model.*; */ public class AsyncMethodFinder { private Set asyncMethods = new HashSet<>(); + private Map asyncFamilyMethods = new HashMap<>(); + private Set readonlyAsyncMethods = Collections.unmodifiableSet(asyncMethods); + private Set readonlyAsyncFamilyMethods = Collections.unmodifiableSet(asyncFamilyMethods.keySet()); private CallGraph callGraph; private Diagnostics diagnostics; private ListableClassReaderSource classSource; @@ -42,7 +44,11 @@ public class AsyncMethodFinder { } public Set getAsyncMethods() { - return asyncMethods; + return readonlyAsyncMethods; + } + + public Set getAsyncFamilyMethods() { + return readonlyAsyncFamilyMethods; } public void find(ListableClassReaderSource classSource) { @@ -58,6 +64,17 @@ public class AsyncMethodFinder { } } } + for (String clsName : classSource.getClassNames()) { + ClassReader cls = classSource.get(clsName); + for (MethodReader method : cls.getMethods()) { + addToFamily(method.getReference()); + } + } + for (Map.Entry entry : new ArrayList<>(asyncFamilyMethods.entrySet())) { + if (!entry.getValue()) { + asyncFamilyMethods.remove(entry.getKey()); + } + } } private void add(MethodReference methodRef) { @@ -98,6 +115,44 @@ public class AsyncMethodFinder { } } + private boolean addToFamily(MethodReference methodRef) { + Boolean cachedResult = asyncFamilyMethods.get(methodRef); + if (cachedResult != null) { + return cachedResult; + } + boolean result = addToFamilyCacheMiss(methodRef); + asyncFamilyMethods.put(methodRef, result); + return result; + } + + private boolean addToFamilyCacheMiss(MethodReference methodRef) { + if (asyncMethods.contains(methodRef)) { + return true; + } + ClassReader cls = classSource.get(methodRef.getClassName()); + if (cls == null) { + return false; + } + List parents = new ArrayList<>(); + if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) { + parents.add(cls.getParent()); + } + parents.addAll(cls.getInterfaces()); + + Set visited = new HashSet<>(); + Set overriden = new HashSet<>(); + for (String parent : parents) { + findOverridenMethods(new MethodReference(parent, methodRef.getDescriptor()), overriden, visited); + } + + for (MethodReference overridenMethod : overriden) { + if (addToFamily(overridenMethod)) { + return true; + } + } + return false; + } + private void findOverridenMethods(MethodReference methodRef, Set result, Set visited) { if (!visited.add(methodRef)) { diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index e964c15b3..435603082 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -90,6 +90,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { private boolean cancelled; private ListableClassHolderSource writtenClasses; private Set asyncMethods = new HashSet<>(); + private Set asyncFamilyMethods = new HashSet<>(); TeaVM(ClassReaderSource classSource, ClassLoader classLoader) { this.classSource = classSource; @@ -397,7 +398,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository { SourceWriterBuilder builder = new SourceWriterBuilder(naming); builder.setMinified(minifying); SourceWriter sourceWriter = builder.build(writer); - Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this, asyncMethods, diagnostics); + Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this, asyncMethods, asyncFamilyMethods, + diagnostics); renderer.setProperties(properties); if (debugEmitter != null) { int classIndex = 0; @@ -539,6 +541,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { AsyncMethodFinder asyncFinder = new AsyncMethodFinder(dependencyChecker.getCallGraph(), diagnostics); asyncFinder.find(classes); asyncMethods.addAll(asyncFinder.getAsyncMethods()); + asyncFamilyMethods.addAll(asyncFinder.getAsyncFamilyMethods()); progressListener.phaseStarted(TeaVMPhase.DECOMPILATION, classes.getClassNames().size()); Decompiler decompiler = new Decompiler(classes, classLoader, asyncFinder.getAsyncMethods()); diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index 638b4db73..ec07f8bfa 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -412,7 +412,6 @@ function $rt_asyncError(e) { } function $rt_asyncAdapter(f) { return function() { - var e; var result; var args = Array.prototype.slice.apply(arguments); var $return = args.pop(); diff --git a/teavm-samples/teavm-samples-benchmark/pom.xml b/teavm-samples/teavm-samples-benchmark/pom.xml index 711bcca06..bbf7e22d0 100644 --- a/teavm-samples/teavm-samples-benchmark/pom.xml +++ b/teavm-samples/teavm-samples-benchmark/pom.xml @@ -91,7 +91,7 @@ ${project.build.directory}/generated/js/teavm org.teavm.samples.benchmark.teavm.BenchmarkStarter SEPARATE - false + true true