Speed-up TeaVM compiler on large applications

This commit is contained in:
konsoletyper 2015-03-09 16:22:19 +03:00
parent 93c7fb52b4
commit fe2adc4675
19 changed files with 140 additions and 108 deletions

View File

@ -129,7 +129,7 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
method.getResult().propagate(agent.getType("[java.lang.Object"));
allClassesNode.connect(method.getResult().getArrayItem());
method.getResult().getArrayItem().addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
initConstructor(agent, type.getName(), location);
}
});

View File

@ -81,7 +81,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
private void achieveGetLength(final DependencyAgent agent, final MethodDependency method) {
method.getVariable(1).addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
if (!type.getName().startsWith("[")) {
MethodReference cons = new MethodReference(IllegalArgumentException.class, "<init>", void.class);
agent.linkMethod(cons, null).use();
@ -128,7 +128,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
private void achieveGet(final DependencyAgent agent, final MethodDependency method) {
method.getVariable(1).getArrayItem().connect(method.getResult());
method.getVariable(1).addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
if (type.getName().startsWith("[")) {
String typeName = type.getName().substring(1);
for (int i = 0; i < primitiveTypes.length; ++i) {

View File

@ -71,7 +71,15 @@ public final class FileNameEncoder {
sb.append(c);
break;
}
}
String str = sb.toString();
sb.setLength(0);
for (int i = 0; i < str.length(); i += 100) {
if (i > 0) {
sb.append('/');
}
int j = Math.min(i + 100, str.length());
sb.append(str.substring(i, j));
}
return sb.toString();
}

View File

@ -15,6 +15,8 @@
*/
package org.teavm.dependency;
import java.util.Collection;
import org.teavm.callgraph.CallGraph;
import org.teavm.common.ServiceRepository;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.*;
@ -23,20 +25,97 @@ import org.teavm.model.*;
*
* @author Alexey Andreev
*/
public interface DependencyAgent extends DependencyInfo, ServiceRepository {
DependencyNode createNode();
public class DependencyAgent implements DependencyInfo, ServiceRepository {
private DependencyChecker checker;
DependencyAgentType getType(String name);
String generateClassName();
void submitClass(ClassHolder cls);
MethodDependency linkMethod(MethodReference methodRef, CallLocation callLocation);
ClassDependency linkClass(String className, CallLocation callLocation);
FieldDependency linkField(FieldReference fieldRef, CallLocation callLocation);
Diagnostics getDiagnostics();
DependencyAgent(DependencyChecker checker) {
this.checker = checker;
}
public DependencyNode createNode() {
return checker.createNode();
}
public DependencyType getType(String name) {
return checker.getType(name);
}
public String generateClassName() {
return checker.generateClassName();
}
public void submitClass(ClassHolder cls) {
checker.submitClass(cls);
}
public MethodDependency linkMethod(MethodReference methodRef, CallLocation callLocation) {
return checker.linkMethod(methodRef, callLocation);
}
public ClassDependency linkClass(String className, CallLocation callLocation) {
return checker.linkClass(className, callLocation);
}
public FieldDependency linkField(FieldReference fieldRef, CallLocation callLocation) {
return checker.linkField(fieldRef, callLocation);
}
public Diagnostics getDiagnostics() {
return checker.getDiagnostics();
}
@Override
public <T> T getService(Class<T> type) {
return checker.getService(type);
}
@Override
public ClassReaderSource getClassSource() {
return checker.getClassSource();
}
@Override
public ClassLoader getClassLoader() {
return checker.getClassLoader();
}
@Override
public Collection<MethodReference> getAchievableMethods() {
return checker.getAchievableMethods();
}
@Override
public Collection<FieldReference> getAchievableFields() {
return checker.getAchievableFields();
}
@Override
public Collection<String> getAchievableClasses() {
return checker.getAchievableClasses();
}
@Override
public FieldDependencyInfo getField(FieldReference fieldRef) {
return checker.getField(fieldRef);
}
@Override
public MethodDependencyInfo getMethod(MethodReference methodRef) {
return checker.getMethod(methodRef);
}
@Override
public MethodDependencyInfo getMethodImplementation(MethodReference methodRef) {
return checker.getMethodImplementation(methodRef);
}
@Override
public ClassDependencyInfo getClass(String className) {
return checker.getClass(className);
}
@Override
public CallGraph getCallGraph() {
return checker.getCallGraph();
}
}

View File

@ -1,26 +0,0 @@
/*
* Copyright 2014 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.dependency;
/**
*
* @author Alexey Andreev
*/
public interface DependencyAgentType {
String getName();
DependencyAgent getDependencyAgent();
}

View File

@ -48,7 +48,7 @@ import org.teavm.model.util.ModelUtils;
*
* @author Alexey Andreev
*/
public class DependencyChecker implements DependencyInfo, DependencyAgent {
public class DependencyChecker implements DependencyInfo {
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
private int classNameSuffix;
private DependencyClassSource classSource;
@ -67,6 +67,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
private boolean interrupted;
private Diagnostics diagnostics;
DefaultCallGraph callGraph = new DefaultCallGraph();
private DependencyAgent agent;
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
Diagnostics diagnostics) {
@ -108,6 +109,12 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return createClassDependency(preimage);
}
});
agent = new DependencyAgent(this);
}
public DependencyAgent getAgent() {
return agent;
}
public DependencyCheckerInterruptor getInterruptor() {
@ -122,7 +129,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return interrupted;
}
@Override
public DependencyType getType(String name) {
DependencyType type = typeMap.get(name);
if (type == null) {
@ -133,7 +139,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return type;
}
@Override
public DependencyNode createNode() {
return new DependencyNode(this);
}
@ -148,19 +153,17 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return classLoader;
}
@Override
public String generateClassName() {
return "$$teavm_generated_class$$" + classNameSuffix++;
}
@Override
public void submitClass(ClassHolder cls) {
classSource.submit(ModelUtils.copyClass(cls));
}
public void addDependencyListener(DependencyListener listener) {
listeners.add(listener);
listener.started(this);
listener.started(agent);
}
public void addClassTransformer(ClassHolderTransformer transformer) {
@ -199,7 +202,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
});
}
@Override
public ClassDependency linkClass(String className, CallLocation callLocation) {
ClassDependency dep = classCache.map(className);
boolean added = true;
@ -211,7 +213,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
}
if (!dep.isMissing() && added) {
for (DependencyListener listener : listeners) {
listener.classAchieved(DependencyChecker.this, className, callLocation);
listener.classAchieved(agent, className, callLocation);
}
}
return dep;
@ -247,7 +249,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return dependency;
}
@Override
public MethodDependency linkMethod(MethodReference methodRef, CallLocation callLocation) {
if (methodRef == null) {
throw new IllegalArgumentException();
@ -265,7 +266,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
MethodDependency graph = methodCache.map(methodRef);
if (!graph.isMissing() && added) {
for (DependencyListener listener : listeners) {
listener.methodAchieved(this, graph, callLocation);
listener.methodAchieved(agent, graph, callLocation);
}
activateDependencyPlugin(graph, callLocation);
}
@ -392,7 +393,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return classCache.getCachedPreimages();
}
@Override
public FieldDependency linkField(final FieldReference fieldRef, final CallLocation location) {
boolean added = true;
if (location != null) {
@ -408,7 +408,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
}
if (!dep.isMissing() && added) {
for (DependencyListener listener : listeners) {
listener.fieldAchieved(DependencyChecker.this, dep, location);
listener.fieldAchieved(agent, dep, location);
}
}
return dep;
@ -443,7 +443,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
private void activateDependencyPlugin(MethodDependency methodDep, CallLocation location) {
attachDependencyPlugin(methodDep);
if (methodDep.dependencyPlugin != null) {
methodDep.dependencyPlugin.methodAchieved(this, methodDep, location);
methodDep.dependencyPlugin.methodAchieved(agent, methodDep, location);
}
}
@ -497,12 +497,10 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
}
}
@Override
public <T> T getService(Class<T> type) {
return services.getService(type);
}
@Override
public Diagnostics getDiagnostics() {
return diagnostics;
}

View File

@ -20,5 +20,5 @@ package org.teavm.dependency;
* @author Alexey Andreev
*/
public interface DependencyConsumer {
void consume(DependencyAgentType type);
void consume(DependencyType type);
}

View File

@ -99,7 +99,7 @@ class DependencyGraphBuilder {
}
@Override
public void consume(DependencyAgentType type) {
public void consume(DependencyType type) {
for (int i = 0; i < exceptions.length; ++i) {
if (exceptions[i] == null || isAssignableFrom(checker.getClassSource(), exceptions[i],
type.getName())) {
@ -139,7 +139,7 @@ class DependencyGraphBuilder {
}
@Override
public void consume(DependencyAgentType type) {
public void consume(DependencyType type) {
String className = type.getName();
if (DependencyChecker.shouldLog) {
System.out.println("Virtual call of " + methodDesc + " detected on " + node.getTag() + ". " +
@ -262,7 +262,7 @@ class DependencyGraphBuilder {
final ClassReader targetClass = dependencyChecker.getClassSource().get(targetClsName);
if (targetClass != null) {
valueNode.connect(receiverNode, new DependencyTypeFilter() {
@Override public boolean match(DependencyAgentType type) {
@Override public boolean match(DependencyType type) {
if (targetClass.getName().equals("java.lang.Object")) {
return true;
}
@ -392,7 +392,7 @@ class DependencyGraphBuilder {
DependencyNode arrayNode = nodes[array.getIndex()];
final DependencyNode receiverNode = nodes[receiver.getIndex()];
arrayNode.addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
receiverNode.propagate(type);
}
});

View File

@ -39,11 +39,7 @@ public class DependencyNode implements ValueDependencyInfo {
this.degree = degree;
}
public void propagate(DependencyAgentType agentType) {
if (!(agentType instanceof DependencyType)) {
throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
}
DependencyType type = (DependencyType)agentType;
public void propagate(DependencyType type) {
if (type.getDependencyChecker() != dependencyChecker) {
throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
}
@ -61,15 +57,11 @@ public class DependencyNode implements ValueDependencyInfo {
}
}
public void propagate(DependencyAgentType[] agentTypes) {
public void propagate(DependencyType[] agentTypes) {
DependencyType[] types = new DependencyType[agentTypes.length];
int j = 0;
for (int i = 0; i < agentTypes.length; ++i) {
DependencyAgentType agentType = agentTypes[i];
if (!(agentType instanceof DependencyType)) {
throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
}
DependencyType type = (DependencyType)agentType;
DependencyType type = agentTypes[i];
if (type.getDependencyChecker() != dependencyChecker) {
throw new IllegalArgumentException("The given type does not belong to the same dependency checker");
}
@ -121,7 +113,7 @@ public class DependencyNode implements ValueDependencyInfo {
arrayItemNode.tag = tag + "[";
}
arrayItemNode.addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
DependencyNode.this.propagate(type);
}
});
@ -134,12 +126,8 @@ public class DependencyNode implements ValueDependencyInfo {
return arrayItemNode != null && arrayItemNode.types.isEmpty();
}
public boolean hasType(DependencyAgentType type) {
if (!(type instanceof DependencyType)) {
return false;
}
DependencyType typeImpl = (DependencyType)type;
return typeImpl.getDependencyChecker() == dependencyChecker && types.get(typeImpl.index);
public boolean hasType(DependencyType type) {
return type.getDependencyChecker() == dependencyChecker && types.get(type.index);
}
@Override

View File

@ -32,7 +32,7 @@ class DependencyNodeToNodeTransition implements DependencyConsumer {
}
@Override
public void consume(DependencyAgentType type) {
public void consume(DependencyType type) {
if (filter != null && !filter.match(type)) {
return;
}

View File

@ -19,7 +19,7 @@ package org.teavm.dependency;
*
* @author Alexey Andreev
*/
public class DependencyType implements DependencyAgentType {
public class DependencyType {
private DependencyChecker dependencyChecker;
private String name;
int index;
@ -30,17 +30,15 @@ public class DependencyType implements DependencyAgentType {
this.index = index;
}
public DependencyChecker getDependencyChecker() {
DependencyChecker getDependencyChecker() {
return dependencyChecker;
}
@Override
public String getName() {
return name;
}
@Override
public DependencyAgent getDependencyAgent() {
return dependencyChecker;
return dependencyChecker.getAgent();
}
}

View File

@ -20,5 +20,5 @@ package org.teavm.dependency;
* @author Alexey Andreev
*/
public interface DependencyTypeFilter {
boolean match(DependencyAgentType type);
boolean match(DependencyType type);
}

View File

@ -47,7 +47,7 @@ public class MethodDependency implements MethodDependencyInfo {
}
public DependencyAgent getDependencyAgent() {
return dependencyChecker;
return dependencyChecker.getAgent();
}
@Override

View File

@ -240,7 +240,8 @@ public class TeaVMTool {
}
vmBuilder.setClassLoader(classLoader).setClassSource(cachedClassSource);
} else {
vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader));
vmBuilder.setClassLoader(classLoader).setClassSource(new PreOptimizingClassHolderSource(
new ClasspathClassHolderSource(classLoader)));
}
vm = vmBuilder.build();
if (progressListener != null) {

View File

@ -20,22 +20,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.java.html.js.JavaScriptBody;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyAgentType;
import org.teavm.dependency.DependencyConsumer;
import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.DependencyNode;
import org.teavm.dependency.FieldDependency;
import org.teavm.dependency.MethodDependency;
import org.teavm.model.AnnotationReader;
import org.teavm.model.AnnotationValue;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.dependency.*;
import org.teavm.model.*;
/**
*
@ -56,7 +42,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
public OneDirectionalConnection(DependencyNode target) {
this.target = target;
}
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
target.propagate(type);
}
}
@ -190,7 +176,7 @@ public class JavaScriptBodyDependency implements DependencyListener {
this.caller = caller;
this.superClass = agent.getClassSource().get(superMethod.getOwnerName());
}
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
if (!isAssignableFrom(superClass, type.getName())) {
return;
}

View File

@ -125,7 +125,7 @@ public class JSNativeGenerator implements Injector, DependencyPlugin {
case "function":
for (int i = 0; i < method.getReference().parameterCount(); ++i) {
method.getVariable(i).addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
achieveFunctorMethods(agent, type.getName(), method);
}
});

View File

@ -41,7 +41,7 @@ public class ClassLookupDependencySupport implements DependencyListener {
MethodReference ref = method.getReference();
if (ref.getClassName().equals(Platform.class.getName()) && ref.getName().equals("lookupClass")) {
allClasses.addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
ClassReader cls = agent.getClassSource().get(type.getName());
if (cls == null) {
return;

View File

@ -48,7 +48,7 @@ public class EnumDependencySupport implements DependencyListener {
allEnums.connect(method.getResult().getArrayItem());
final MethodReference ref = method.getReference();
allEnums.addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
ClassReader cls = agent.getClassSource().get(type.getName());
MethodReader method = cls.getMethod(new MethodDescriptor("values",
ValueType.arrayOf(ValueType.object(cls.getName()))));

View File

@ -53,7 +53,7 @@ public class NewInstanceDependencySupport implements DependencyListener {
allClassesNode.connect(method.getResult());
final MethodReference methodRef = reader.getReference();
method.getResult().addConsumer(new DependencyConsumer() {
@Override public void consume(DependencyAgentType type) {
@Override public void consume(DependencyType type) {
attachConstructor(agent, type.getName(), new CallLocation(methodRef));
}
});