mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24: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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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 boolean incremental;
|
||||
private RegularMethodNodeCache astCache;
|
||||
private ProgramCache programCache;
|
||||
|
||||
public File getOutputDir() {
|
||||
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.png", "res/toggle-small.png");
|
||||
resourceToFile(prefix + "/junit.html", "junit.html");
|
||||
final ClassHolderSource classSource = new PreOptimizingClassHolderSource(
|
||||
new ClasspathClassHolderSource(classLoader));
|
||||
ClassHolderSource classSource = new ClasspathClassHolderSource(classLoader);
|
||||
if (incremental) {
|
||||
classSource = new PreOptimizingClassHolderSource(classSource);
|
||||
}
|
||||
for (String testClass : testClasses) {
|
||||
ClassHolder classHolder = classSource.get(testClass);
|
||||
if (classHolder == null) {
|
||||
|
@ -158,6 +161,7 @@ public class TeaVMTestTool {
|
|||
astCache = new EmptyRegularMethodNodeCache();
|
||||
if (incremental) {
|
||||
astCache = new InMemoryRegularMethodNodeCache();
|
||||
programCache = new InMemoryProgramCache();
|
||||
}
|
||||
File allTestsFile = new File(outputDir, "tests/all.js");
|
||||
try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) {
|
||||
|
@ -221,11 +225,12 @@ public class TeaVMTestTool {
|
|||
executor = threadedExecutor;
|
||||
}
|
||||
for (final MethodReference method : testMethods) {
|
||||
final ClassHolderSource builderClassSource = classSource;
|
||||
executor.execute(new Runnable() {
|
||||
@Override public void run() {
|
||||
log.debug("Building test for " + method);
|
||||
try {
|
||||
decompileClassesForTest(classLoader, new CopyClassHolderSource(classSource), method,
|
||||
decompileClassesForTest(classLoader, new CopyClassHolderSource(builderClassSource), method,
|
||||
fileNames.get(method));
|
||||
} catch (IOException e) {
|
||||
log.error("Error generating JavaScript", e);
|
||||
|
@ -300,6 +305,7 @@ public class TeaVMTestTool {
|
|||
.build();
|
||||
vm.setIncremental(incremental);
|
||||
vm.setAstCache(astCache);
|
||||
vm.setProgramCache(programCache);
|
||||
vm.setProperties(properties);
|
||||
vm.setMinifying(minifying);
|
||||
vm.installPlugins();
|
||||
|
|
|
@ -30,8 +30,7 @@ import org.teavm.model.*;
|
|||
import org.teavm.model.util.ListingBuilder;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
import org.teavm.model.util.RegisterAllocator;
|
||||
import org.teavm.optimization.ClassSetOptimizer;
|
||||
import org.teavm.optimization.Devirtualization;
|
||||
import org.teavm.optimization.*;
|
||||
import org.teavm.vm.spi.RendererListener;
|
||||
import org.teavm.vm.spi.TeaVMHost;
|
||||
import org.teavm.vm.spi.TeaVMPlugin;
|
||||
|
@ -80,6 +79,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
private Map<Class<?>, Object> services = new HashMap<>();
|
||||
private Properties properties = new Properties();
|
||||
private DebugInformationEmitter debugEmitter;
|
||||
private ProgramCache programCache;
|
||||
private RegularMethodNodeCache astCache = new EmptyRegularMethodNodeCache();
|
||||
private boolean incremental;
|
||||
|
||||
|
@ -172,6 +172,14 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
this.astCache = methodAstCache;
|
||||
}
|
||||
|
||||
public ProgramCache getProgramCache() {
|
||||
return programCache;
|
||||
}
|
||||
|
||||
public void setProgramCache(ProgramCache programCache) {
|
||||
this.programCache = programCache;
|
||||
}
|
||||
|
||||
public boolean isIncremental() {
|
||||
return incremental;
|
||||
}
|
||||
|
@ -333,27 +341,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
if (!incremental) {
|
||||
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
|
||||
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());
|
||||
List<ClassNode> clsNodes = modelToAst(classSet);
|
||||
|
||||
// Render
|
||||
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, dependencyChecker.getClassSource());
|
||||
|
@ -440,29 +429,61 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
}
|
||||
}
|
||||
|
||||
private void allocateRegisters(ListableClassHolderSource classes) {
|
||||
for (String className : classes.getClassNames()) {
|
||||
private List<ClassNode> modelToAst(ListableClassHolderSource classes) {
|
||||
Decompiler decompiler = new Decompiler(classes, 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<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 (final MethodHolder method : cls.getMethods()) {
|
||||
if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) {
|
||||
RegisterAllocator allocator = new RegisterAllocator();
|
||||
Program program = ProgramUtils.copy(method.getProgram());
|
||||
allocator.allocateRegisters(method, program);
|
||||
method.setProgram(program);
|
||||
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) {
|
||||
for (String className : classes.getClassNames()) {
|
||||
ClassHolder classHolder = classes.get(className);
|
||||
printModifiers(writer, classHolder);
|
||||
writer.println("class " + className);
|
||||
for (MethodHolder method : classHolder.getMethods()) {
|
||||
logMethodBytecode(writer, method);
|
||||
private void processMethod(MethodHolder method) {
|
||||
if (method.getProgram() == null) {
|
||||
return;
|
||||
}
|
||||
Program optimizedProgram = incremental && programCache != null ?
|
||||
programCache.get(method.getReference()) : null;
|
||||
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) {
|
||||
|
|
|
@ -163,6 +163,7 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
tool.setOutputDir(outputDir);
|
||||
tool.setNumThreads(numThreads);
|
||||
tool.setMinifying(minifying);
|
||||
tool.setIncremental(incremental);
|
||||
if (properties != null) {
|
||||
tool.getProperties().putAll(properties);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user