mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Add lazy compilation pipeline that can work a little bit faster in incremental compiler
This commit is contained in:
parent
5be34dcf44
commit
35ca7fd152
|
@ -200,12 +200,12 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void beforeOptimizations(Program program, MethodReader method, ListableClassReaderSource classSource) {
|
||||
public void beforeOptimizations(Program program, MethodReader method) {
|
||||
nullCheckInsertion.transformProgram(program, method.getReference());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterOptimizations(Program program, MethodReader method, ListableClassReaderSource classSource) {
|
||||
public void afterOptimizations(Program program, MethodReader method) {
|
||||
clinitInsertionTransformer.apply(method, program);
|
||||
classInitializerEliminator.apply(program);
|
||||
classInitializerTransformer.transform(program);
|
||||
|
|
|
@ -70,7 +70,6 @@ import org.teavm.model.ClassReaderSource;
|
|||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
@ -293,11 +292,11 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void beforeOptimizations(Program program, MethodReader method, ListableClassReaderSource classSource) {
|
||||
public void beforeOptimizations(Program program, MethodReader method) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterOptimizations(Program program, MethodReader method, ListableClassReaderSource classSource) {
|
||||
public void afterOptimizations(Program program, MethodReader method) {
|
||||
clinitInsertionTransformer.apply(method, program);
|
||||
}
|
||||
|
||||
|
@ -628,5 +627,5 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
|||
public ClassReaderSource getClassSource() {
|
||||
return classSource;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -301,11 +301,11 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void beforeOptimizations(Program program, MethodReader method, ListableClassReaderSource classSource) {
|
||||
public void beforeOptimizations(Program program, MethodReader method) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterOptimizations(Program program, MethodReader method, ListableClassReaderSource classes) {
|
||||
public void afterOptimizations(Program program, MethodReader method) {
|
||||
clinitInsertionTransformer.apply(method, program);
|
||||
classInitializerEliminator.apply(program);
|
||||
classInitializerTransformer.transform(program);
|
||||
|
|
|
@ -736,6 +736,15 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
|
|||
node.transitions = null;
|
||||
node.transitionList = null;
|
||||
node.method = null;
|
||||
}
|
||||
|
||||
allNodes.clear();
|
||||
classSource.cleanup();
|
||||
agent.cleanup();
|
||||
}
|
||||
|
||||
public void cleanupTypes() {
|
||||
for (DependencyNode node : allNodes) {
|
||||
if (node.typeSet != null) {
|
||||
node.typeSet.cleanup();
|
||||
}
|
||||
|
@ -747,10 +756,6 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
|
|||
dependency.variableNodes[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
allNodes.clear();
|
||||
classSource.cleanup();
|
||||
agent.cleanup();
|
||||
}
|
||||
|
||||
static class ReportEntry {
|
||||
|
|
|
@ -34,8 +34,13 @@ import org.teavm.model.instructions.PutFieldInstruction;
|
|||
|
||||
public class Linker {
|
||||
private static final MethodDescriptor clinitDescriptor = new MethodDescriptor("<clinit>", void.class);
|
||||
private DependencyInfo dependency;
|
||||
|
||||
public void link(DependencyInfo dependency, ClassHolder cls) {
|
||||
public Linker(DependencyInfo dependency) {
|
||||
this.dependency = dependency;
|
||||
}
|
||||
|
||||
public void link(ClassHolder cls) {
|
||||
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
|
||||
MethodReference methodRef = method.getReference();
|
||||
MethodDependencyInfo methodDep = dependency.getMethod(methodRef);
|
||||
|
@ -45,7 +50,7 @@ public class Linker {
|
|||
method.getModifiers().add(ElementModifier.ABSTRACT);
|
||||
method.setProgram(null);
|
||||
} else if (method.getProgram() != null) {
|
||||
link(dependency, method);
|
||||
link(method.getReference(), method.getProgram());
|
||||
}
|
||||
}
|
||||
for (FieldHolder field : cls.getFields().toArray(new FieldHolder[0])) {
|
||||
|
@ -56,8 +61,7 @@ public class Linker {
|
|||
}
|
||||
}
|
||||
|
||||
private void link(DependencyInfo dependency, MethodHolder method) {
|
||||
Program program = method.getProgram();
|
||||
public void link(MethodReference method, Program program) {
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (Instruction insn : block) {
|
||||
|
@ -96,8 +100,8 @@ public class Linker {
|
|||
}
|
||||
}
|
||||
|
||||
private void insertClinit(DependencyInfo dependency, String className, MethodHolder method, Instruction insn) {
|
||||
if (className.equals(method.getOwnerName())) {
|
||||
private void insertClinit(DependencyInfo dependency, String className, MethodReference method, Instruction insn) {
|
||||
if (className.equals(method.getClassName())) {
|
||||
return;
|
||||
}
|
||||
ClassReader cls = dependency.getClassSource().get(className);
|
||||
|
|
|
@ -15,10 +15,13 @@
|
|||
*/
|
||||
package org.teavm.model;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class MethodHolder extends MemberHolder implements MethodReader {
|
||||
private MethodDescriptor descriptor;
|
||||
private ClassHolder owner;
|
||||
private Program program;
|
||||
private Function<MethodHolder, Program> programSupplier;
|
||||
private AnnotationValue annotationDefault;
|
||||
private AnnotationContainer[] parameterAnnotations;
|
||||
private MethodReference reference;
|
||||
|
@ -110,6 +113,13 @@ public class MethodHolder extends MemberHolder implements MethodReader {
|
|||
|
||||
@Override
|
||||
public Program getProgram() {
|
||||
if (program == null && programSupplier != null) {
|
||||
program = programSupplier.apply(this);
|
||||
if (program != null) {
|
||||
program.setMethod(this);
|
||||
}
|
||||
programSupplier = null;
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
|
@ -118,11 +128,20 @@ public class MethodHolder extends MemberHolder implements MethodReader {
|
|||
this.program.setMethod(null);
|
||||
}
|
||||
this.program = program;
|
||||
this.programSupplier = null;
|
||||
if (this.program != null) {
|
||||
this.program.setMethod(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setProgramSupplier(Function<MethodHolder, Program> programSupplier) {
|
||||
if (this.program != null) {
|
||||
this.program.setMethod(null);
|
||||
}
|
||||
this.program = null;
|
||||
this.programSupplier = programSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationValue getAnnotationDefault() {
|
||||
return annotationDefault;
|
||||
|
|
|
@ -25,7 +25,6 @@ import org.teavm.dependency.ValueDependencyInfo;
|
|||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
@ -35,15 +34,13 @@ import org.teavm.model.instructions.InvokeInstruction;
|
|||
|
||||
public class Devirtualization {
|
||||
private DependencyInfo dependency;
|
||||
private ClassReaderSource classSource;
|
||||
private ClassHierarchy hierarchy;
|
||||
private Set<MethodReference> virtualMethods = new HashSet<>();
|
||||
private Set<? extends MethodReference> readonlyVirtualMethods = Collections.unmodifiableSet(virtualMethods);
|
||||
|
||||
public Devirtualization(DependencyInfo dependency, ClassReaderSource classSource) {
|
||||
public Devirtualization(DependencyInfo dependency, ClassHierarchy hierarchy) {
|
||||
this.dependency = dependency;
|
||||
this.classSource = classSource;
|
||||
hierarchy = new ClassHierarchy(classSource);
|
||||
this.hierarchy = hierarchy;
|
||||
}
|
||||
|
||||
public void apply(MethodHolder method) {
|
||||
|
@ -82,7 +79,7 @@ public class Devirtualization {
|
|||
if (className.startsWith("[")) {
|
||||
className = "java.lang.Object";
|
||||
}
|
||||
ClassReader cls = classSource.get(className);
|
||||
ClassReader cls = hierarchy.getClassSource().get(className);
|
||||
if (cls == null || !isSuperclass.test(cls.getName(), false)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -16,13 +16,10 @@
|
|||
package org.teavm.model.optimization;
|
||||
|
||||
import org.teavm.dependency.DependencyInfo;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReader;
|
||||
|
||||
public interface MethodOptimizationContext {
|
||||
MethodReader getMethod();
|
||||
|
||||
DependencyInfo getDependencyInfo();
|
||||
|
||||
ClassReaderSource getClassSource();
|
||||
}
|
||||
|
|
|
@ -56,9 +56,6 @@ public class UnusedVariableElimination implements MethodOptimization {
|
|||
}
|
||||
|
||||
public boolean optimize(MethodReader method, Program program) {
|
||||
if (method.getProgram() == null) {
|
||||
return false;
|
||||
}
|
||||
Graph graph = VariableUsageGraphBuilder.build(program);
|
||||
boolean[] escaping = VariableEscapeAnalyzer.findEscapingVariables(program);
|
||||
boolean[] used = new boolean[escaping.length];
|
||||
|
|
|
@ -30,7 +30,7 @@ public class MissingItemsProcessor {
|
|||
private ClassHierarchy hierarchy;
|
||||
private Diagnostics diagnostics;
|
||||
private List<Instruction> instructionsToAdd = new ArrayList<>();
|
||||
private MethodHolder methodHolder;
|
||||
private MethodReference methodRef;
|
||||
private Program program;
|
||||
private Collection<String> reachableClasses;
|
||||
private Collection<MethodReference> reachableMethods;
|
||||
|
@ -54,8 +54,12 @@ public class MissingItemsProcessor {
|
|||
}
|
||||
|
||||
public void processMethod(MethodHolder method) {
|
||||
this.methodHolder = method;
|
||||
this.program = method.getProgram();
|
||||
processMethod(method.getReference(), method.getProgram());
|
||||
}
|
||||
|
||||
public void processMethod(MethodReference method, Program program) {
|
||||
this.methodRef = method;
|
||||
this.program = program;
|
||||
boolean wasModified = false;
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
|
@ -131,7 +135,7 @@ public class MissingItemsProcessor {
|
|||
if (!reachableClasses.contains(className) || !dependencyInfo.getClass(className).isMissing()) {
|
||||
return true;
|
||||
}
|
||||
diagnostics.error(new CallLocation(methodHolder.getReference(), location), "Class {{c0}} was not found",
|
||||
diagnostics.error(new CallLocation(methodRef, location), "Class {{c0}} was not found",
|
||||
className);
|
||||
emitExceptionThrow(location, NoClassDefFoundError.class.getName(), "Class not found: " + className);
|
||||
return false;
|
||||
|
@ -159,7 +163,7 @@ public class MissingItemsProcessor {
|
|||
return true;
|
||||
}
|
||||
|
||||
diagnostics.error(new CallLocation(methodHolder.getReference(), location), "Method {{m0}} was not found",
|
||||
diagnostics.error(new CallLocation(methodRef, location), "Method {{m0}} was not found",
|
||||
method);
|
||||
emitExceptionThrow(location, NoSuchMethodError.class.getName(), "Method not found: " + method);
|
||||
return true;
|
||||
|
@ -177,7 +181,7 @@ public class MissingItemsProcessor {
|
|||
return true;
|
||||
}
|
||||
|
||||
diagnostics.error(new CallLocation(methodHolder.getReference(), location), "Method {{m0}} was not found",
|
||||
diagnostics.error(new CallLocation(methodRef, location), "Method {{m0}} was not found",
|
||||
method);
|
||||
emitExceptionThrow(location, NoSuchMethodError.class.getName(), "Method not found: " + method);
|
||||
return true;
|
||||
|
@ -190,7 +194,7 @@ public class MissingItemsProcessor {
|
|||
if (!reachableFields.contains(field) || !dependencyInfo.getField(field).isMissing()) {
|
||||
return true;
|
||||
}
|
||||
diagnostics.error(new CallLocation(methodHolder.getReference(), location), "Field {{f0}} was not found",
|
||||
diagnostics.error(new CallLocation(methodRef, location), "Field {{f0}} was not found",
|
||||
field);
|
||||
emitExceptionThrow(location, NoSuchFieldError.class.getName(), "Field not found: " + field);
|
||||
return true;
|
||||
|
|
|
@ -17,19 +17,33 @@ package org.teavm.model.util;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.AnnotationContainer;
|
||||
import org.teavm.model.AnnotationContainerReader;
|
||||
import org.teavm.model.AnnotationHolder;
|
||||
import org.teavm.model.AnnotationReader;
|
||||
import org.teavm.model.AnnotationValue;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.FieldHolder;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
|
||||
public final class ModelUtils {
|
||||
private ModelUtils() {
|
||||
}
|
||||
|
||||
public static ClassHolder copyClass(ClassReader original, ClassHolder target) {
|
||||
return copyClass(original, target, true);
|
||||
}
|
||||
|
||||
public static ClassHolder copyClass(ClassReader original, ClassHolder target, boolean withPrograms) {
|
||||
target.setLevel(original.getLevel());
|
||||
target.getModifiers().addAll(original.readModifiers());
|
||||
target.setParent(original.getParent());
|
||||
target.getInterfaces().addAll(original.getInterfaces());
|
||||
for (MethodReader method : original.getMethods()) {
|
||||
target.addMethod(copyMethod(method));
|
||||
target.addMethod(copyMethod(method, withPrograms));
|
||||
}
|
||||
for (FieldReader field : original.getFields()) {
|
||||
target.addField(copyField(field));
|
||||
|
@ -40,14 +54,22 @@ public final class ModelUtils {
|
|||
}
|
||||
|
||||
public static ClassHolder copyClass(ClassReader original) {
|
||||
return copyClass(original, new ClassHolder(original.getName()));
|
||||
return copyClass(original, true);
|
||||
}
|
||||
|
||||
public static ClassHolder copyClass(ClassReader original, boolean withPrograms) {
|
||||
return copyClass(original, new ClassHolder(original.getName()), withPrograms);
|
||||
}
|
||||
|
||||
public static MethodHolder copyMethod(MethodReader method) {
|
||||
return copyMethod(method, true);
|
||||
}
|
||||
|
||||
public static MethodHolder copyMethod(MethodReader method, boolean withProgram) {
|
||||
MethodHolder copy = new MethodHolder(method.getDescriptor());
|
||||
copy.setLevel(method.getLevel());
|
||||
copy.getModifiers().addAll(method.readModifiers());
|
||||
if (method.getProgram() != null) {
|
||||
if (method.getProgram() != null && withProgram) {
|
||||
copy.setProgram(ProgramUtils.copy(method.getProgram()));
|
||||
}
|
||||
copyAnnotations(method.getAnnotations(), copy.getAnnotations());
|
||||
|
|
|
@ -26,7 +26,6 @@ import org.teavm.common.MutableGraphNode;
|
|||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.Incoming;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Phi;
|
||||
import org.teavm.model.Program;
|
||||
|
@ -36,7 +35,7 @@ import org.teavm.model.instructions.AssignInstruction;
|
|||
import org.teavm.model.instructions.JumpInstruction;
|
||||
|
||||
public class RegisterAllocator {
|
||||
public void allocateRegisters(MethodReader method, Program program, boolean debuggerFriendly) {
|
||||
public void allocateRegisters(MethodReference method, Program program, boolean debuggerFriendly) {
|
||||
insertPhiArgumentsCopies(program);
|
||||
InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
|
||||
LivenessAnalyzer liveness = new LivenessAnalyzer();
|
||||
|
@ -60,7 +59,7 @@ public class RegisterAllocator {
|
|||
for (int cls : classArray) {
|
||||
maxClass = Math.max(maxClass, cls + 1);
|
||||
}
|
||||
int[] categories = getVariableCategories(program, method.getReference());
|
||||
int[] categories = getVariableCategories(program, method);
|
||||
String[] names = getVariableNames(program, debuggerFriendly);
|
||||
colorer.colorize(MutableGraphNode.toGraph(interferenceGraph), colors, categories, names);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.cache.AlwaysStaleCacheStatus;
|
||||
|
@ -44,6 +45,7 @@ import org.teavm.dependency.DependencyListener;
|
|||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.Linker;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.dependency.MethodDependencyInfo;
|
||||
import org.teavm.diagnostics.AccumulationDiagnostics;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.diagnostics.ProblemProvider;
|
||||
|
@ -52,6 +54,9 @@ import org.teavm.model.ClassHolder;
|
|||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldHolder;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
|
@ -141,6 +146,10 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
private ProgramDependencyExtractor programDependencyExtractor = new ProgramDependencyExtractor();
|
||||
private List<Predicate<MethodReference>> additionalVirtualMethods = new ArrayList<>();
|
||||
private int lastKnownClasses;
|
||||
private int compileProgressReportStart;
|
||||
private int compileProgressReportLimit;
|
||||
private int compileProgressLimit;
|
||||
private int compileProgressValue;
|
||||
|
||||
TeaVM(TeaVMBuilder builder) {
|
||||
target = builder.target;
|
||||
|
@ -378,63 +387,97 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
cacheStatus.addSynthesizedClasses(dependencyAnalyzer::isSynthesizedClass);
|
||||
dependencyAnalyzer.setInterruptor(null);
|
||||
|
||||
// Link
|
||||
if (wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
ListableClassHolderSource classSet = link(dependencyAnalyzer);
|
||||
writtenClasses = classSet;
|
||||
if (wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Optimize and allocate registers
|
||||
int maxOptimizationProgress = classSet.getClassNames().size();
|
||||
if (optimizationLevel == TeaVMOptimizationLevel.ADVANCED) {
|
||||
maxOptimizationProgress *= 2;
|
||||
} else if (optimizationLevel == TeaVMOptimizationLevel.FULL) {
|
||||
maxOptimizationProgress *= 3;
|
||||
}
|
||||
reportPhase(TeaVMPhase.OPTIMIZATION, maxOptimizationProgress);
|
||||
|
||||
int progress = 0;
|
||||
if (optimizationLevel != TeaVMOptimizationLevel.SIMPLE) {
|
||||
progress = devirtualize(progress, classSet, dependencyAnalyzer);
|
||||
boolean isLazy = optimizationLevel == TeaVMOptimizationLevel.SIMPLE;
|
||||
ListableClassHolderSource classSet;
|
||||
if (isLazy) {
|
||||
initCompileProgress(1000);
|
||||
classSet = lazyPipeline();
|
||||
} else {
|
||||
initCompileProgress(500);
|
||||
classSet = eagerPipeline();
|
||||
if (wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dependencyAnalyzer.cleanup();
|
||||
progress = inline(progress, classSet, dependencyAnalyzer);
|
||||
if (wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
optimize(progress, classSet);
|
||||
if (wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Render
|
||||
try {
|
||||
reportPhase(TeaVMPhase.RENDERING, 1000);
|
||||
if (!isLazy) {
|
||||
compileProgressReportStart = 500;
|
||||
compileProgressReportLimit = 1000;
|
||||
}
|
||||
target.emit(classSet, buildTarget, outputName);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error generating output files", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void initCompileProgress(int limit) {
|
||||
reportPhase(TeaVMPhase.COMPILING, 1000);
|
||||
compileProgressReportStart = 0;
|
||||
compileProgressReportLimit = limit;
|
||||
}
|
||||
|
||||
private ListableClassHolderSource eagerPipeline() {
|
||||
compileProgressValue = 0;
|
||||
compileProgressLimit = dependencyAnalyzer.getReachableClasses().size();
|
||||
if (optimizationLevel == TeaVMOptimizationLevel.ADVANCED) {
|
||||
compileProgressLimit *= 3;
|
||||
} else if (optimizationLevel == TeaVMOptimizationLevel.FULL) {
|
||||
compileProgressLimit *= 4;
|
||||
} else {
|
||||
compileProgressLimit *= 2;
|
||||
}
|
||||
|
||||
ListableClassHolderSource classSet = link(dependencyAnalyzer);
|
||||
writtenClasses = classSet;
|
||||
if (wasCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (optimizationLevel != TeaVMOptimizationLevel.SIMPLE) {
|
||||
devirtualize(classSet);
|
||||
if (wasCancelled()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
dependencyAnalyzer.cleanupTypes();
|
||||
|
||||
inline(classSet);
|
||||
if (wasCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Optimize and allocate registers
|
||||
optimize(classSet);
|
||||
if (wasCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return classSet;
|
||||
}
|
||||
|
||||
private ListableClassHolderSource lazyPipeline() {
|
||||
return new PostProcessingClassHolderSource();
|
||||
}
|
||||
|
||||
public ListableClassHolderSource link(DependencyAnalyzer dependency) {
|
||||
reportPhase(TeaVMPhase.LINKING, dependency.getReachableClasses().size());
|
||||
Linker linker = new Linker();
|
||||
Linker linker = new Linker(dependency);
|
||||
MutableClassHolderSource cutClasses = new MutableClassHolderSource();
|
||||
MissingItemsProcessor missingItemsProcessor = new MissingItemsProcessor(dependency,
|
||||
dependency.getClassHierarchy(), diagnostics);
|
||||
if (wasCancelled()) {
|
||||
return cutClasses;
|
||||
}
|
||||
int index = 0;
|
||||
|
||||
if (wasCancelled()) {
|
||||
return cutClasses;
|
||||
|
@ -442,14 +485,13 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
|
||||
for (String className : dependency.getReachableClasses()) {
|
||||
ClassReader clsReader = dependency.getClassSource().get(className);
|
||||
if (clsReader == null) {
|
||||
continue;
|
||||
if (clsReader != null) {
|
||||
ClassHolder cls = ModelUtils.copyClass(clsReader);
|
||||
cutClasses.putClassHolder(cls);
|
||||
missingItemsProcessor.processClass(cls);
|
||||
linker.link(cls);
|
||||
}
|
||||
ClassHolder cls = ModelUtils.copyClass(clsReader);
|
||||
cutClasses.putClassHolder(cls);
|
||||
missingItemsProcessor.processClass(cls);
|
||||
linker.link(dependency, cls);
|
||||
reportProgress(++index);
|
||||
reportCompileProgress(++compileProgressValue);
|
||||
if (wasCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
@ -469,12 +511,17 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
}
|
||||
}
|
||||
|
||||
private int devirtualize(int progress, ListableClassHolderSource classes, DependencyInfo dependency) {
|
||||
private void reportCompileProgress(int progress) {
|
||||
reportProgress(compileProgressReportStart
|
||||
+ progress * (compileProgressReportLimit - compileProgressReportStart) / compileProgressLimit);
|
||||
}
|
||||
|
||||
private void devirtualize(ListableClassHolderSource classes) {
|
||||
if (wasCancelled()) {
|
||||
return progress;
|
||||
return;
|
||||
}
|
||||
Devirtualization devirtualization = new Devirtualization(dependency, classes);
|
||||
int index = 0;
|
||||
Devirtualization devirtualization = new Devirtualization(dependencyAnalyzer,
|
||||
dependencyAnalyzer.getClassHierarchy());
|
||||
for (String className : classes.getClassNames()) {
|
||||
ClassHolder cls = classes.get(className);
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
|
@ -482,34 +529,33 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
devirtualization.apply(method);
|
||||
}
|
||||
}
|
||||
reportProgress(++index);
|
||||
reportCompileProgress(++compileProgressValue);
|
||||
if (wasCancelled()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
virtualMethods = devirtualization.getVirtualMethods();
|
||||
return progress;
|
||||
}
|
||||
|
||||
private int inline(int progress, ListableClassHolderSource classes, DependencyInfo dependencyInfo) {
|
||||
private void inline(ListableClassHolderSource classes) {
|
||||
if (optimizationLevel != TeaVMOptimizationLevel.FULL) {
|
||||
return progress;
|
||||
return;
|
||||
}
|
||||
|
||||
Map<MethodReference, Program> inlinedPrograms = new HashMap<>();
|
||||
Inlining inlining = new Inlining(new ClassHierarchy(classes), dependencyInfo);
|
||||
Inlining inlining = new Inlining(new ClassHierarchy(classes), dependencyAnalyzer);
|
||||
for (String className : classes.getClassNames()) {
|
||||
ClassHolder cls = classes.get(className);
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
if (method.getProgram() != null) {
|
||||
Program program = ProgramUtils.copy(method.getProgram());
|
||||
MethodOptimizationContextImpl context = new MethodOptimizationContextImpl(method, classes);
|
||||
MethodOptimizationContextImpl context = new MethodOptimizationContextImpl(method);
|
||||
inlining.apply(program, method.getReference());
|
||||
new UnusedVariableElimination().optimize(context, program);
|
||||
inlinedPrograms.put(method.getReference(), program);
|
||||
}
|
||||
}
|
||||
reportProgress(++progress);
|
||||
reportCompileProgress(++compileProgressValue);
|
||||
if (wasCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
@ -523,25 +569,22 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
private int optimize(int progress, ListableClassHolderSource classSource) {
|
||||
private void optimize(ListableClassHolderSource classSource) {
|
||||
for (String className : classSource.getClassNames()) {
|
||||
ClassHolder cls = classSource.get(className);
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
processMethod(method, classSource);
|
||||
optimizeMethod(method);
|
||||
}
|
||||
reportProgress(++progress);
|
||||
reportCompileProgress(++compileProgressValue);
|
||||
if (wasCancelled()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
private void processMethod(MethodHolder method, ListableClassReaderSource classSource) {
|
||||
private void optimizeMethod(MethodHolder method) {
|
||||
if (method.getProgram() == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -549,36 +592,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
Program optimizedProgram = !cacheStatus.isStaleMethod(method.getReference())
|
||||
? programCache.get(method.getReference(), cacheStatus)
|
||||
: null;
|
||||
MethodOptimizationContextImpl context = new MethodOptimizationContextImpl(method, classSource);
|
||||
if (optimizedProgram == null) {
|
||||
optimizedProgram = ProgramUtils.copy(method.getProgram());
|
||||
target.beforeOptimizations(optimizedProgram, method, classSource);
|
||||
|
||||
if (optimizedProgram.basicBlockCount() > 0) {
|
||||
boolean changed;
|
||||
do {
|
||||
changed = false;
|
||||
for (MethodOptimization optimization : getOptimizations()) {
|
||||
try {
|
||||
changed |= optimization.optimize(context, optimizedProgram);
|
||||
} catch (Exception | AssertionError e) {
|
||||
ListingBuilder listingBuilder = new ListingBuilder();
|
||||
String listing = listingBuilder.buildListing(optimizedProgram, "");
|
||||
System.err.println("Error optimizing program for method " + method.getReference()
|
||||
+ ":\n" + listing);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
} while (changed);
|
||||
|
||||
target.afterOptimizations(optimizedProgram, method, classSource);
|
||||
if (target.requiresRegisterAllocation()) {
|
||||
RegisterAllocator allocator = new RegisterAllocator();
|
||||
allocator.allocateRegisters(method, optimizedProgram,
|
||||
optimizationLevel == TeaVMOptimizationLevel.SIMPLE);
|
||||
}
|
||||
}
|
||||
|
||||
optimizedProgram = optimizeMethodCacheMiss(method, ProgramUtils.copy(method.getProgram()));
|
||||
Program finalProgram = optimizedProgram;
|
||||
programCache.store(method.getReference(), finalProgram,
|
||||
() -> programDependencyExtractor.extractDependencies(finalProgram));
|
||||
|
@ -586,13 +601,43 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
method.setProgram(optimizedProgram);
|
||||
}
|
||||
|
||||
private Program optimizeMethodCacheMiss(MethodHolder method, Program optimizedProgram) {
|
||||
target.beforeOptimizations(optimizedProgram, method);
|
||||
|
||||
if (optimizedProgram.basicBlockCount() > 0) {
|
||||
MethodOptimizationContextImpl context = new MethodOptimizationContextImpl(method);
|
||||
boolean changed;
|
||||
do {
|
||||
changed = false;
|
||||
for (MethodOptimization optimization : getOptimizations()) {
|
||||
try {
|
||||
changed |= optimization.optimize(context, optimizedProgram);
|
||||
} catch (Exception | AssertionError e) {
|
||||
ListingBuilder listingBuilder = new ListingBuilder();
|
||||
String listing = listingBuilder.buildListing(optimizedProgram, "");
|
||||
System.err.println("Error optimizing program for method " + method.getReference()
|
||||
+ ":\n" + listing);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
} while (changed);
|
||||
|
||||
target.afterOptimizations(optimizedProgram, method);
|
||||
if (target.requiresRegisterAllocation()) {
|
||||
RegisterAllocator allocator = new RegisterAllocator();
|
||||
allocator.allocateRegisters(method.getReference(), optimizedProgram,
|
||||
optimizationLevel == TeaVMOptimizationLevel.SIMPLE);
|
||||
}
|
||||
}
|
||||
|
||||
return optimizedProgram;
|
||||
}
|
||||
|
||||
class MethodOptimizationContextImpl implements MethodOptimizationContext {
|
||||
private MethodReader method;
|
||||
private ClassReaderSource classSource;
|
||||
|
||||
MethodOptimizationContextImpl(MethodReader method, ClassReaderSource classSource) {
|
||||
MethodOptimizationContextImpl(MethodReader method) {
|
||||
this.method = method;
|
||||
this.classSource = classSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -604,11 +649,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
public DependencyInfo getDependencyInfo() {
|
||||
return dependencyAnalyzer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassReaderSource getClassSource() {
|
||||
return classSource;
|
||||
}
|
||||
}
|
||||
|
||||
private List<MethodOptimization> getOptimizations() {
|
||||
|
@ -742,8 +782,72 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TeaVMProgressFeedback reportProgress(int progres) {
|
||||
return progressListener.progressReached(progres);
|
||||
public TeaVMProgressFeedback reportProgress(int progress) {
|
||||
progress = progress * (compileProgressReportLimit - compileProgressReportStart) / 1000
|
||||
+ compileProgressReportStart;
|
||||
return progressListener.progressReached(progress);
|
||||
}
|
||||
};
|
||||
|
||||
class PostProcessingClassHolderSource implements ListableClassHolderSource {
|
||||
private Linker linker = new Linker(dependencyAnalyzer);
|
||||
private MissingItemsProcessor missingItemsProcessor = new MissingItemsProcessor(dependencyAnalyzer,
|
||||
dependencyAnalyzer.getClassHierarchy(), diagnostics);
|
||||
private Map<String, ClassHolder> cache = new HashMap<>();
|
||||
private Set<String> classNames = Collections.unmodifiableSet(new HashSet<>(
|
||||
dependencyAnalyzer.getReachableClasses()));
|
||||
|
||||
@Override
|
||||
public ClassHolder get(String name) {
|
||||
return cache.computeIfAbsent(name, className -> {
|
||||
ClassReader classReader = dependencyAnalyzer.getClassSource().get(className);
|
||||
if (classReader == null) {
|
||||
return null;
|
||||
}
|
||||
ClassHolder cls = ModelUtils.copyClass(classReader, false);
|
||||
|
||||
for (FieldHolder field : cls.getFields().toArray(new FieldHolder[0])) {
|
||||
FieldReference fieldRef = new FieldReference(cls.getName(), field.getName());
|
||||
if (dependencyAnalyzer.getField(fieldRef) == null) {
|
||||
cls.removeField(field);
|
||||
}
|
||||
}
|
||||
|
||||
Function<MethodHolder, Program> programSupplier = method -> {
|
||||
Program program = !cacheStatus.isStaleMethod(method.getReference())
|
||||
? programCache.get(method.getReference(), cacheStatus)
|
||||
: null;
|
||||
if (program == null) {
|
||||
program = ProgramUtils.copy(classReader.getMethod(method.getDescriptor()).getProgram());
|
||||
missingItemsProcessor.processMethod(method.getReference(), program);
|
||||
linker.link(method.getReference(), program);
|
||||
program = optimizeMethodCacheMiss(method, program);
|
||||
Program finalProgram = program;
|
||||
programCache.store(method.getReference(), finalProgram,
|
||||
() -> programDependencyExtractor.extractDependencies(finalProgram));
|
||||
}
|
||||
return program;
|
||||
};
|
||||
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
|
||||
MethodDependencyInfo methodDep = dependencyAnalyzer.getMethod(method.getReference());
|
||||
if (methodDep == null) {
|
||||
cls.removeMethod(method);
|
||||
} else if (!methodDep.isUsed()) {
|
||||
method.getModifiers().add(ElementModifier.ABSTRACT);
|
||||
} else {
|
||||
MethodReader methodReader = classReader.getMethod(method.getDescriptor());
|
||||
if (methodReader != null && methodReader.getProgram() != null) {
|
||||
method.setProgramSupplier(programSupplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cls;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getClassNames() {
|
||||
return classNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,5 @@ package org.teavm.vm;
|
|||
|
||||
public enum TeaVMPhase {
|
||||
DEPENDENCY_ANALYSIS,
|
||||
LINKING,
|
||||
OPTIMIZATION,
|
||||
RENDERING
|
||||
COMPILING
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.teavm.dependency.DependencyAnalyzer;
|
|||
import org.teavm.dependency.DependencyListener;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ListableClassHolderSource;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.vm.spi.TeaVMHostExtension;
|
||||
|
@ -39,9 +38,9 @@ public interface TeaVMTarget {
|
|||
|
||||
void contributeDependencies(DependencyAnalyzer dependencyAnalyzer);
|
||||
|
||||
void beforeOptimizations(Program program, MethodReader method, ListableClassReaderSource classSource);
|
||||
void beforeOptimizations(Program program, MethodReader method);
|
||||
|
||||
void afterOptimizations(Program program, MethodReader method, ListableClassReaderSource classSource);
|
||||
void afterOptimizations(Program program, MethodReader method);
|
||||
|
||||
void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException;
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.junit.Test;
|
|||
import org.junit.rules.TestName;
|
||||
import org.teavm.dependency.DependencyInfo;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ListingParseUtils;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
|
@ -111,11 +110,6 @@ public class ScalarReplacementTest {
|
|||
public DependencyInfo getDependencyInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassReaderSource getClassSource() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
new ScalarReplacement().optimize(context, program);
|
||||
|
|
|
@ -426,14 +426,8 @@ public final class TeaVMRunner {
|
|||
case DEPENDENCY_ANALYSIS:
|
||||
System.out.print("Analyzing classes...");
|
||||
break;
|
||||
case LINKING:
|
||||
System.out.print("Linking methods...");
|
||||
break;
|
||||
case OPTIMIZATION:
|
||||
System.out.print("Optimizing code...");
|
||||
break;
|
||||
case RENDERING:
|
||||
System.out.print("Generating output...");
|
||||
case COMPILING:
|
||||
System.out.print("Compiling...");
|
||||
break;
|
||||
}
|
||||
currentPhase = phase;
|
||||
|
|
|
@ -981,18 +981,10 @@ public class CodeServlet extends HttpServlet {
|
|||
switch (phase) {
|
||||
case DEPENDENCY_ANALYSIS:
|
||||
start = 0;
|
||||
end = 400;
|
||||
break;
|
||||
case LINKING:
|
||||
start = 400;
|
||||
end = 500;
|
||||
break;
|
||||
case OPTIMIZATION:
|
||||
case COMPILING:
|
||||
start = 500;
|
||||
end = 750;
|
||||
break;
|
||||
case RENDERING:
|
||||
start = 750;
|
||||
end = 1000;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -180,12 +180,8 @@ class TeaVMBuild {
|
|||
switch (phase) {
|
||||
case DEPENDENCY_ANALYSIS:
|
||||
return "Discovering classes to compile";
|
||||
case LINKING:
|
||||
return "Resolving method invocations";
|
||||
case OPTIMIZATION:
|
||||
return "Optimizing code";
|
||||
case RENDERING:
|
||||
return "Building JS file";
|
||||
case COMPILING:
|
||||
return "Compiling";
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user