mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-10 08:54:11 -08:00
Cache optimized programs with allocated registers
This commit is contained in:
parent
520008913e
commit
b4a172b8f7
|
@ -91,6 +91,15 @@ public class Decompiler {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getClassOrdering(Collection<String> classNames) {
|
||||||
|
List<String> sequence = new ArrayList<>();
|
||||||
|
Set<String> visited = new HashSet<>();
|
||||||
|
for (String className : classNames) {
|
||||||
|
orderClasses(className, visited, sequence);
|
||||||
|
}
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
public void addGenerator(MethodReference method, Generator generator) {
|
public void addGenerator(MethodReference method, Generator generator) {
|
||||||
generators.put(method, generator);
|
generators.put(method, generator);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class InMemoryProgramCache implements ProgramCache {
|
||||||
|
private Map<MethodReference, Program> cache = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Program get(MethodReference method) {
|
||||||
|
return cache.get(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void store(MethodReference method, Program program) {
|
||||||
|
cache.put(method, program);
|
||||||
|
}
|
||||||
|
}
|
27
teavm-core/src/main/java/org/teavm/model/ProgramCache.java
Normal file
27
teavm-core/src/main/java/org/teavm/model/ProgramCache.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public interface ProgramCache {
|
||||||
|
Program get(MethodReference method);
|
||||||
|
|
||||||
|
void store(MethodReference method, Program program);
|
||||||
|
}
|
|
@ -53,6 +53,7 @@ public class TeaVMTestTool {
|
||||||
private TeaVMToolLog log = new EmptyTeaVMToolLog();
|
private TeaVMToolLog log = new EmptyTeaVMToolLog();
|
||||||
private boolean incremental;
|
private boolean incremental;
|
||||||
private RegularMethodNodeCache astCache;
|
private RegularMethodNodeCache astCache;
|
||||||
|
private ProgramCache programCache;
|
||||||
|
|
||||||
public File getOutputDir() {
|
public File getOutputDir() {
|
||||||
return outputDir;
|
return outputDir;
|
||||||
|
@ -144,8 +145,10 @@ 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 PreOptimizingClassHolderSource(
|
ClassHolderSource classSource = new ClasspathClassHolderSource(classLoader);
|
||||||
new ClasspathClassHolderSource(classLoader));
|
if (incremental) {
|
||||||
|
classSource = new PreOptimizingClassHolderSource(classSource);
|
||||||
|
}
|
||||||
for (String testClass : testClasses) {
|
for (String testClass : testClasses) {
|
||||||
ClassHolder classHolder = classSource.get(testClass);
|
ClassHolder classHolder = classSource.get(testClass);
|
||||||
if (classHolder == null) {
|
if (classHolder == null) {
|
||||||
|
@ -158,6 +161,7 @@ public class TeaVMTestTool {
|
||||||
astCache = new EmptyRegularMethodNodeCache();
|
astCache = new EmptyRegularMethodNodeCache();
|
||||||
if (incremental) {
|
if (incremental) {
|
||||||
astCache = new InMemoryRegularMethodNodeCache();
|
astCache = new InMemoryRegularMethodNodeCache();
|
||||||
|
programCache = new InMemoryProgramCache();
|
||||||
}
|
}
|
||||||
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")) {
|
||||||
|
@ -221,11 +225,12 @@ public class TeaVMTestTool {
|
||||||
executor = threadedExecutor;
|
executor = threadedExecutor;
|
||||||
}
|
}
|
||||||
for (final MethodReference method : testMethods) {
|
for (final MethodReference method : testMethods) {
|
||||||
|
final ClassHolderSource builderClassSource = classSource;
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
log.debug("Building test for " + method);
|
log.debug("Building test for " + method);
|
||||||
try {
|
try {
|
||||||
decompileClassesForTest(classLoader, new CopyClassHolderSource(classSource), method,
|
decompileClassesForTest(classLoader, new CopyClassHolderSource(builderClassSource), method,
|
||||||
fileNames.get(method));
|
fileNames.get(method));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Error generating JavaScript", e);
|
log.error("Error generating JavaScript", e);
|
||||||
|
@ -300,6 +305,7 @@ public class TeaVMTestTool {
|
||||||
.build();
|
.build();
|
||||||
vm.setIncremental(incremental);
|
vm.setIncremental(incremental);
|
||||||
vm.setAstCache(astCache);
|
vm.setAstCache(astCache);
|
||||||
|
vm.setProgramCache(programCache);
|
||||||
vm.setProperties(properties);
|
vm.setProperties(properties);
|
||||||
vm.setMinifying(minifying);
|
vm.setMinifying(minifying);
|
||||||
vm.installPlugins();
|
vm.installPlugins();
|
||||||
|
|
|
@ -30,8 +30,7 @@ import org.teavm.model.*;
|
||||||
import org.teavm.model.util.ListingBuilder;
|
import org.teavm.model.util.ListingBuilder;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
import org.teavm.model.util.ProgramUtils;
|
||||||
import org.teavm.model.util.RegisterAllocator;
|
import org.teavm.model.util.RegisterAllocator;
|
||||||
import org.teavm.optimization.ClassSetOptimizer;
|
import org.teavm.optimization.*;
|
||||||
import org.teavm.optimization.Devirtualization;
|
|
||||||
import org.teavm.vm.spi.RendererListener;
|
import org.teavm.vm.spi.RendererListener;
|
||||||
import org.teavm.vm.spi.TeaVMHost;
|
import org.teavm.vm.spi.TeaVMHost;
|
||||||
import org.teavm.vm.spi.TeaVMPlugin;
|
import org.teavm.vm.spi.TeaVMPlugin;
|
||||||
|
@ -80,6 +79,7 @@ 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 ProgramCache programCache;
|
||||||
private RegularMethodNodeCache astCache = new EmptyRegularMethodNodeCache();
|
private RegularMethodNodeCache astCache = new EmptyRegularMethodNodeCache();
|
||||||
private boolean incremental;
|
private boolean incremental;
|
||||||
|
|
||||||
|
@ -172,6 +172,14 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
this.astCache = methodAstCache;
|
this.astCache = methodAstCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ProgramCache getProgramCache() {
|
||||||
|
return programCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgramCache(ProgramCache programCache) {
|
||||||
|
this.programCache = programCache;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isIncremental() {
|
public boolean isIncremental() {
|
||||||
return incremental;
|
return incremental;
|
||||||
}
|
}
|
||||||
|
@ -333,27 +341,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
if (!incremental) {
|
if (!incremental) {
|
||||||
devirtualize(classSet, dependencyChecker);
|
devirtualize(classSet, dependencyChecker);
|
||||||
}
|
}
|
||||||
ClassSetOptimizer optimizer = new ClassSetOptimizer();
|
|
||||||
optimizer.optimizeAll(classSet);
|
|
||||||
allocateRegisters(classSet);
|
|
||||||
if (bytecodeLogging) {
|
|
||||||
try {
|
|
||||||
logBytecode(new PrintWriter(new OutputStreamWriter(logStream, "UTF-8")), classSet);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
// Just don't do anything
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decompile
|
List<ClassNode> clsNodes = modelToAst(classSet);
|
||||||
Decompiler decompiler = new Decompiler(classSet, classLoader);
|
|
||||||
decompiler.setRegularMethodCache(incremental ? astCache : null);
|
|
||||||
for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) {
|
|
||||||
decompiler.addGenerator(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
for (MethodReference injectedMethod : methodInjectors.keySet()) {
|
|
||||||
decompiler.addMethodToPass(injectedMethod);
|
|
||||||
}
|
|
||||||
List<ClassNode> clsNodes = decompiler.decompile(classSet.getClassNames());
|
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, dependencyChecker.getClassSource());
|
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, dependencyChecker.getClassSource());
|
||||||
|
@ -440,29 +429,61 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void allocateRegisters(ListableClassHolderSource classes) {
|
private List<ClassNode> modelToAst(ListableClassHolderSource classes) {
|
||||||
for (String className : classes.getClassNames()) {
|
Decompiler decompiler = new Decompiler(classes, classLoader);
|
||||||
ClassHolder cls = classes.get(className);
|
decompiler.setRegularMethodCache(incremental ? astCache : null);
|
||||||
for (final MethodHolder method : cls.getMethods()) {
|
|
||||||
if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) {
|
for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) {
|
||||||
RegisterAllocator allocator = new RegisterAllocator();
|
decompiler.addGenerator(entry.getKey(), entry.getValue());
|
||||||
Program program = ProgramUtils.copy(method.getProgram());
|
|
||||||
allocator.allocateRegisters(method, program);
|
|
||||||
method.setProgram(program);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
for (MethodReference injectedMethod : methodInjectors.keySet()) {
|
||||||
|
decompiler.addMethodToPass(injectedMethod);
|
||||||
|
}
|
||||||
|
List<String> classOrder = decompiler.getClassOrdering(classes.getClassNames());
|
||||||
|
List<ClassNode> classNodes = new ArrayList<>();
|
||||||
|
try (PrintWriter bytecodeLogger = bytecodeLogging ?
|
||||||
|
new PrintWriter(new OutputStreamWriter(logStream, "UTF-8")) : null) {
|
||||||
|
for (String className : classOrder) {
|
||||||
|
ClassHolder cls = classes.get(className);
|
||||||
|
for (MethodHolder method : cls.getMethods()) {
|
||||||
|
processMethod(method);
|
||||||
|
if (bytecodeLogging) {
|
||||||
|
logMethodBytecode(bytecodeLogger, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
classNodes.add(decompiler.decompile(cls));
|
||||||
|
}
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new AssertionError("UTF-8 is expected to be supported");
|
||||||
|
}
|
||||||
|
return classNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logBytecode(PrintWriter writer, ListableClassHolderSource classes) {
|
private void processMethod(MethodHolder method) {
|
||||||
for (String className : classes.getClassNames()) {
|
if (method.getProgram() == null) {
|
||||||
ClassHolder classHolder = classes.get(className);
|
return;
|
||||||
printModifiers(writer, classHolder);
|
}
|
||||||
writer.println("class " + className);
|
Program optimizedProgram = incremental && programCache != null ?
|
||||||
for (MethodHolder method : classHolder.getMethods()) {
|
programCache.get(method.getReference()) : null;
|
||||||
logMethodBytecode(writer, method);
|
if (optimizedProgram == null) {
|
||||||
|
optimizedProgram = ProgramUtils.copy(method.getProgram());
|
||||||
|
if (optimizedProgram.basicBlockCount() > 0) {
|
||||||
|
for (MethodOptimization optimization : getOptimizations()) {
|
||||||
|
optimization.optimize(method, optimizedProgram);
|
||||||
|
}
|
||||||
|
RegisterAllocator allocator = new RegisterAllocator();
|
||||||
|
allocator.allocateRegisters(method, optimizedProgram);
|
||||||
|
}
|
||||||
|
if (incremental && programCache != null) {
|
||||||
|
programCache.store(method.getReference(), optimizedProgram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
method.setProgram(optimizedProgram);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MethodOptimization> getOptimizations() {
|
||||||
|
return Arrays.<MethodOptimization>asList(new ArrayUnwrapMotion(), new LoopInvariantMotion(),
|
||||||
|
new GlobalValueNumbering(), new UnusedVariableElimination());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logMethodBytecode(PrintWriter writer, MethodHolder method) {
|
private void logMethodBytecode(PrintWriter writer, MethodHolder method) {
|
||||||
|
|
|
@ -163,6 +163,7 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
||||||
tool.setOutputDir(outputDir);
|
tool.setOutputDir(outputDir);
|
||||||
tool.setNumThreads(numThreads);
|
tool.setNumThreads(numThreads);
|
||||||
tool.setMinifying(minifying);
|
tool.setMinifying(minifying);
|
||||||
|
tool.setIncremental(incremental);
|
||||||
if (properties != null) {
|
if (properties != null) {
|
||||||
tool.getProperties().putAll(properties);
|
tool.getProperties().putAll(properties);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user