Adds AST caching

This commit is contained in:
konsoletyper 2014-09-04 18:21:09 +04:00
parent f740782881
commit 520008913e
8 changed files with 175 additions and 5 deletions

View File

@ -72,6 +72,7 @@
<phase>process-test-classes</phase> <phase>process-test-classes</phase>
<configuration> <configuration>
<minifying>false</minifying> <minifying>false</minifying>
<incremental>true</incremental>
<numThreads>1</numThreads> <numThreads>1</numThreads>
<properties> <properties>
<java.util.Locale.available>en, en_US, en_GB, ru, ru_RU</java.util.Locale.available> <java.util.Locale.available>en, en_US, en_GB, ru, ru_RU</java.util.Locale.available>

View File

@ -44,12 +44,21 @@ public class Decompiler {
private RangeTree.Node parentNode; private RangeTree.Node parentNode;
private Map<MethodReference, Generator> generators = new HashMap<>(); private Map<MethodReference, Generator> generators = new HashMap<>();
private Set<MethodReference> methodsToPass = new HashSet<>(); private Set<MethodReference> methodsToPass = new HashSet<>();
private RegularMethodNodeCache regularMethodCache;
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader) { public Decompiler(ClassHolderSource classSource, ClassLoader classLoader) {
this.classSource = classSource; this.classSource = classSource;
this.classLoader = classLoader; this.classLoader = classLoader;
} }
public RegularMethodNodeCache getRegularMethodCache() {
return regularMethodCache;
}
public void setRegularMethodCache(RegularMethodNodeCache regularMethodCache) {
this.regularMethodCache = regularMethodCache;
}
public int getGraphSize() { public int getGraphSize() {
return this.graph.size(); return this.graph.size();
} }
@ -165,6 +174,18 @@ public class Decompiler {
} }
public RegularMethodNode decompileRegular(MethodHolder method) { public RegularMethodNode decompileRegular(MethodHolder method) {
if (regularMethodCache == null) {
return decompileRegularCacheMiss(method);
}
RegularMethodNode node = regularMethodCache.get(method.getReference());
if (node == null) {
node = decompileRegularCacheMiss(method);
regularMethodCache.store(method.getReference(), node);
}
return node;
}
public RegularMethodNode decompileRegularCacheMiss(MethodHolder method) {
lastBlockId = 1; lastBlockId = 1;
graph = ProgramUtils.buildControlFlowGraph(method.getProgram()); graph = ProgramUtils.buildControlFlowGraph(method.getProgram());
indexer = new GraphIndexer(graph); indexer = new GraphIndexer(graph);

View File

@ -0,0 +1,34 @@
/*
* 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.javascript;
import org.teavm.javascript.ast.RegularMethodNode;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class EmptyRegularMethodNodeCache implements RegularMethodNodeCache {
@Override
public RegularMethodNode get(MethodReference methodReference) {
return null;
}
@Override
public void store(MethodReference methodReference, RegularMethodNode node) {
}
}

View File

@ -0,0 +1,39 @@
/*
* 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.javascript;
import java.util.HashMap;
import java.util.Map;
import org.teavm.javascript.ast.RegularMethodNode;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class InMemoryRegularMethodNodeCache implements RegularMethodNodeCache {
private Map<MethodReference, RegularMethodNode> cache = new HashMap<>();
@Override
public RegularMethodNode get(MethodReference methodReference) {
return cache.get(methodReference);
}
@Override
public void store(MethodReference methodReference, RegularMethodNode node) {
cache.put(methodReference, node);
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.javascript;
import org.teavm.javascript.ast.RegularMethodNode;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public interface RegularMethodNodeCache {
RegularMethodNode get(MethodReference methodReference);
void store(MethodReference methodReference, RegularMethodNode node);
}

View File

@ -21,6 +21,9 @@ import org.apache.commons.io.IOUtils;
import org.teavm.common.FiniteExecutor; import org.teavm.common.FiniteExecutor;
import org.teavm.common.SimpleFiniteExecutor; import org.teavm.common.SimpleFiniteExecutor;
import org.teavm.common.ThreadPoolFiniteExecutor; import org.teavm.common.ThreadPoolFiniteExecutor;
import org.teavm.javascript.EmptyRegularMethodNodeCache;
import org.teavm.javascript.InMemoryRegularMethodNodeCache;
import org.teavm.javascript.RegularMethodNodeCache;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.parsing.ClasspathClassHolderSource; import org.teavm.parsing.ClasspathClassHolderSource;
import org.teavm.testing.JUnitTestAdapter; import org.teavm.testing.JUnitTestAdapter;
@ -48,6 +51,8 @@ public class TeaVMTestTool {
private List<String> testClasses = new ArrayList<>(); private List<String> testClasses = new ArrayList<>();
private ClassLoader classLoader = TeaVMTestTool.class.getClassLoader(); private ClassLoader classLoader = TeaVMTestTool.class.getClassLoader();
private TeaVMToolLog log = new EmptyTeaVMToolLog(); private TeaVMToolLog log = new EmptyTeaVMToolLog();
private boolean incremental;
private RegularMethodNodeCache astCache;
public File getOutputDir() { public File getOutputDir() {
return outputDir; return outputDir;
@ -113,6 +118,14 @@ public class TeaVMTestTool {
this.log = log; this.log = log;
} }
public boolean isIncremental() {
return incremental;
}
public void setIncremental(boolean incremental) {
this.incremental = incremental;
}
public void generate() throws TeaVMToolException { public void generate() throws TeaVMToolException {
Runnable finalizer = null; Runnable finalizer = null;
try { try {
@ -131,7 +144,8 @@ public class TeaVMTestTool {
resourceToFile(prefix + "/res/toggle-small-expand.png", "res/toggle-small-expand.png"); resourceToFile(prefix + "/res/toggle-small-expand.png", "res/toggle-small-expand.png");
resourceToFile(prefix + "/res/toggle-small.png", "res/toggle-small.png"); resourceToFile(prefix + "/res/toggle-small.png", "res/toggle-small.png");
resourceToFile(prefix + "/junit.html", "junit.html"); resourceToFile(prefix + "/junit.html", "junit.html");
final ClassHolderSource classSource = new ClasspathClassHolderSource(classLoader); final ClassHolderSource classSource = new PreOptimizingClassHolderSource(
new ClasspathClassHolderSource(classLoader));
for (String testClass : testClasses) { for (String testClass : testClasses) {
ClassHolder classHolder = classSource.get(testClass); ClassHolder classHolder = classSource.get(testClass);
if (classHolder == null) { if (classHolder == null) {
@ -141,6 +155,10 @@ public class TeaVMTestTool {
} }
includeAdditionalScripts(classLoader); includeAdditionalScripts(classLoader);
astCache = new EmptyRegularMethodNodeCache();
if (incremental) {
astCache = new InMemoryRegularMethodNodeCache();
}
File allTestsFile = new File(outputDir, "tests/all.js"); File allTestsFile = new File(outputDir, "tests/all.js");
try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) { try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) {
allTestsWriter.write("prepare = function() {\n"); allTestsWriter.write("prepare = function() {\n");
@ -280,6 +298,8 @@ public class TeaVMTestTool {
.setClassLoader(classLoader) .setClassLoader(classLoader)
.setClassSource(classSource) .setClassSource(classSource)
.build(); .build();
vm.setIncremental(incremental);
vm.setAstCache(astCache);
vm.setProperties(properties); vm.setProperties(properties);
vm.setMinifying(minifying); vm.setMinifying(minifying);
vm.installPlugins(); vm.installPlugins();

View File

@ -22,9 +22,7 @@ import org.teavm.common.ServiceRepository;
import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.DebugInformationEmitter;
import org.teavm.debugging.information.SourceLocation; import org.teavm.debugging.information.SourceLocation;
import org.teavm.dependency.*; import org.teavm.dependency.*;
import org.teavm.javascript.Decompiler; import org.teavm.javascript.*;
import org.teavm.javascript.Renderer;
import org.teavm.javascript.RenderingException;
import org.teavm.javascript.ast.ClassNode; import org.teavm.javascript.ast.ClassNode;
import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.Injector; import org.teavm.javascript.ni.Injector;
@ -82,6 +80,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
private Map<Class<?>, Object> services = new HashMap<>(); private Map<Class<?>, Object> services = new HashMap<>();
private Properties properties = new Properties(); private Properties properties = new Properties();
private DebugInformationEmitter debugEmitter; private DebugInformationEmitter debugEmitter;
private RegularMethodNodeCache astCache = new EmptyRegularMethodNodeCache();
private boolean incremental;
TeaVM(ClassReaderSource classSource, ClassLoader classLoader) { TeaVM(ClassReaderSource classSource, ClassLoader classLoader) {
this.classSource = classSource; this.classSource = classSource;
@ -164,6 +164,22 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return new Properties(properties); return new Properties(properties);
} }
public RegularMethodNodeCache getAstCache() {
return astCache;
}
public void setAstCache(RegularMethodNodeCache methodAstCache) {
this.astCache = methodAstCache;
}
public boolean isIncremental() {
return incremental;
}
public void setIncremental(boolean incremental) {
this.incremental = incremental;
}
/** /**
* <p>Adds an entry point. TeaVM guarantees, that all methods that are required by the entry point * <p>Adds an entry point. TeaVM guarantees, that all methods that are required by the entry point
* will be available at run-time in browser. Also you need to specify for each parameter of entry point * will be available at run-time in browser. Also you need to specify for each parameter of entry point
@ -314,7 +330,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
ListableClassHolderSource classSet = linker.link(dependencyChecker); ListableClassHolderSource classSet = linker.link(dependencyChecker);
// Optimize and allocate registers // Optimize and allocate registers
if (!incremental) {
devirtualize(classSet, dependencyChecker); devirtualize(classSet, dependencyChecker);
}
ClassSetOptimizer optimizer = new ClassSetOptimizer(); ClassSetOptimizer optimizer = new ClassSetOptimizer();
optimizer.optimizeAll(classSet); optimizer.optimizeAll(classSet);
allocateRegisters(classSet); allocateRegisters(classSet);
@ -328,6 +346,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
// Decompile // Decompile
Decompiler decompiler = new Decompiler(classSet, classLoader); Decompiler decompiler = new Decompiler(classSet, classLoader);
decompiler.setRegularMethodCache(incremental ? astCache : null);
for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) { for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) {
decompiler.addGenerator(entry.getKey(), entry.getValue()); decompiler.addGenerator(entry.getKey(), entry.getValue());
} }

View File

@ -89,6 +89,9 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
@Parameter @Parameter
private Properties properties; private Properties properties;
@Parameter
private boolean incremental;
private TeaVMTestTool tool = new TeaVMTestTool(); private TeaVMTestTool tool = new TeaVMTestTool();
public void setProject(MavenProject project) { public void setProject(MavenProject project) {
@ -135,6 +138,10 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
this.properties = properties; this.properties = properties;
} }
public void setIncremental(boolean incremental) {
this.incremental = incremental;
}
@Override @Override
public void execute() throws MojoExecutionException, MojoFailureException { public void execute() throws MojoExecutionException, MojoFailureException {
if (System.getProperty("maven.test.skip", "false").equals("true") || if (System.getProperty("maven.test.skip", "false").equals("true") ||