Don't insert $rt_asyncAdapter for methods that don't override async

methods
This commit is contained in:
konsoletyper 2015-02-08 23:12:33 +04:00
parent 2ae7b587d1
commit 62431c493c
5 changed files with 68 additions and 8 deletions

View File

@ -55,6 +55,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
private DeferredCallSite lastCallSite; private DeferredCallSite lastCallSite;
private DeferredCallSite prevCallSite; private DeferredCallSite prevCallSite;
private Set<MethodReference> asyncMethods; private Set<MethodReference> asyncMethods;
private Set<MethodReference> asyncFamilyMethods;
private Diagnostics diagnostics; private Diagnostics diagnostics;
private boolean async; private boolean async;
@ -79,13 +80,15 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
} }
public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader, public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader,
ServiceRepository services, Set<MethodReference> asyncMethods, Diagnostics diagnostics) { ServiceRepository services, Set<MethodReference> asyncMethods, Set<MethodReference> asyncFamilyMethods,
Diagnostics diagnostics) {
this.naming = writer.getNaming(); this.naming = writer.getNaming();
this.writer = writer; this.writer = writer;
this.classSource = classSource; this.classSource = classSource;
this.classLoader = classLoader; this.classLoader = classLoader;
this.services = services; this.services = services;
this.asyncMethods = new HashSet<>(asyncMethods); this.asyncMethods = new HashSet<>(asyncMethods);
this.asyncFamilyMethods = new HashSet<>(asyncFamilyMethods);
this.diagnostics = diagnostics; this.diagnostics = diagnostics;
} }
@ -460,7 +463,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.append(");").ws().append("}"); writer.append(");").ws().append("}");
debugEmitter.emitMethod(null); debugEmitter.emitMethod(null);
if (!method.isAsync()) { if (!method.isAsync() && asyncFamilyMethods.contains(method.getReference())) {
writer.append(",").newLine(); writer.append(",").newLine();
writer.append("\"").append(naming.getNameForAsync(ref)).append("\",").ws(); writer.append("\"").append(naming.getNameForAsync(ref)).append("\",").ws();
writer.append("$rt_asyncAdapter(").appendMethodBody(ref).append(')'); writer.append("$rt_asyncAdapter(").appendMethodBody(ref).append(')');

View File

@ -15,8 +15,7 @@
*/ */
package org.teavm.model.util; package org.teavm.model.util;
import java.util.HashSet; import java.util.*;
import java.util.Set;
import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraph;
import org.teavm.callgraph.CallGraphNode; import org.teavm.callgraph.CallGraphNode;
import org.teavm.callgraph.CallSite; import org.teavm.callgraph.CallSite;
@ -32,6 +31,9 @@ import org.teavm.model.*;
*/ */
public class AsyncMethodFinder { public class AsyncMethodFinder {
private Set<MethodReference> asyncMethods = new HashSet<>(); private Set<MethodReference> asyncMethods = new HashSet<>();
private Map<MethodReference, Boolean> asyncFamilyMethods = new HashMap<>();
private Set<MethodReference> readonlyAsyncMethods = Collections.unmodifiableSet(asyncMethods);
private Set<MethodReference> readonlyAsyncFamilyMethods = Collections.unmodifiableSet(asyncFamilyMethods.keySet());
private CallGraph callGraph; private CallGraph callGraph;
private Diagnostics diagnostics; private Diagnostics diagnostics;
private ListableClassReaderSource classSource; private ListableClassReaderSource classSource;
@ -42,7 +44,11 @@ public class AsyncMethodFinder {
} }
public Set<MethodReference> getAsyncMethods() { public Set<MethodReference> getAsyncMethods() {
return asyncMethods; return readonlyAsyncMethods;
}
public Set<MethodReference> getAsyncFamilyMethods() {
return readonlyAsyncFamilyMethods;
} }
public void find(ListableClassReaderSource classSource) { 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<MethodReference, Boolean> entry : new ArrayList<>(asyncFamilyMethods.entrySet())) {
if (!entry.getValue()) {
asyncFamilyMethods.remove(entry.getKey());
}
}
} }
private void add(MethodReference methodRef) { 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<String> parents = new ArrayList<>();
if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
parents.add(cls.getParent());
}
parents.addAll(cls.getInterfaces());
Set<MethodReference> visited = new HashSet<>();
Set<MethodReference> 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<MethodReference> result, private void findOverridenMethods(MethodReference methodRef, Set<MethodReference> result,
Set<MethodReference> visited) { Set<MethodReference> visited) {
if (!visited.add(methodRef)) { if (!visited.add(methodRef)) {

View File

@ -90,6 +90,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
private boolean cancelled; private boolean cancelled;
private ListableClassHolderSource writtenClasses; private ListableClassHolderSource writtenClasses;
private Set<MethodReference> asyncMethods = new HashSet<>(); private Set<MethodReference> asyncMethods = new HashSet<>();
private Set<MethodReference> asyncFamilyMethods = new HashSet<>();
TeaVM(ClassReaderSource classSource, ClassLoader classLoader) { TeaVM(ClassReaderSource classSource, ClassLoader classLoader) {
this.classSource = classSource; this.classSource = classSource;
@ -397,7 +398,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
SourceWriterBuilder builder = new SourceWriterBuilder(naming); SourceWriterBuilder builder = new SourceWriterBuilder(naming);
builder.setMinified(minifying); builder.setMinified(minifying);
SourceWriter sourceWriter = builder.build(writer); 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); renderer.setProperties(properties);
if (debugEmitter != null) { if (debugEmitter != null) {
int classIndex = 0; int classIndex = 0;
@ -539,6 +541,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
AsyncMethodFinder asyncFinder = new AsyncMethodFinder(dependencyChecker.getCallGraph(), diagnostics); AsyncMethodFinder asyncFinder = new AsyncMethodFinder(dependencyChecker.getCallGraph(), diagnostics);
asyncFinder.find(classes); asyncFinder.find(classes);
asyncMethods.addAll(asyncFinder.getAsyncMethods()); asyncMethods.addAll(asyncFinder.getAsyncMethods());
asyncFamilyMethods.addAll(asyncFinder.getAsyncFamilyMethods());
progressListener.phaseStarted(TeaVMPhase.DECOMPILATION, classes.getClassNames().size()); progressListener.phaseStarted(TeaVMPhase.DECOMPILATION, classes.getClassNames().size());
Decompiler decompiler = new Decompiler(classes, classLoader, asyncFinder.getAsyncMethods()); Decompiler decompiler = new Decompiler(classes, classLoader, asyncFinder.getAsyncMethods());

View File

@ -412,7 +412,6 @@ function $rt_asyncError(e) {
} }
function $rt_asyncAdapter(f) { function $rt_asyncAdapter(f) {
return function() { return function() {
var e;
var result; var result;
var args = Array.prototype.slice.apply(arguments); var args = Array.prototype.slice.apply(arguments);
var $return = args.pop(); var $return = args.pop();

View File

@ -91,7 +91,7 @@
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory> <targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
<mainClass>org.teavm.samples.benchmark.teavm.BenchmarkStarter</mainClass> <mainClass>org.teavm.samples.benchmark.teavm.BenchmarkStarter</mainClass>
<runtime>SEPARATE</runtime> <runtime>SEPARATE</runtime>
<minifying>false</minifying> <minifying>true</minifying>
<debugInformationGenerated>true</debugInformationGenerated> <debugInformationGenerated>true</debugInformationGenerated>
</configuration> </configuration>
</execution> </execution>