Support of multithreaded execution. Performance optimizations.

This commit is contained in:
konsoletyper 2014-01-28 16:46:40 +04:00
parent 0c240f5636
commit 24921c6e80
15 changed files with 213 additions and 66 deletions

View File

@ -53,7 +53,7 @@
<phase>process-test-classes</phase>
<configuration>
<minifying>false</minifying>
<numThreads>1</numThreads>
<numThreads>0</numThreads>
</configuration>
</execution>
</executions>

View File

@ -66,17 +66,19 @@ public class ThreadPoolFiniteExecutor implements FiniteExecutor {
@Override
public void complete() {
synchronized (monitor) {
try {
monitor.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
if (thrownException.get() != null) {
throw thrownException.get();
}
if (runningTasks.get() == 0) {
return;
while (true) {
if (thrownException.get() != null) {
throw thrownException.get();
}
if (runningTasks.get() == 0) {
return;
}
try {
monitor.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
}

View File

@ -40,10 +40,12 @@ public class Decompiler {
private RangeTree codeTree;
private RangeTree.Node currentNode;
private RangeTree.Node parentNode;
private FiniteExecutor executor;
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader) {
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
this.classSource = classSource;
this.classLoader = classLoader;
this.executor = executor;
}
public int getGraphSize() {
@ -70,10 +72,19 @@ public class Decompiler {
for (String className : classNames) {
orderClasses(className, visited, sequence);
}
List<ClassNode> result = new ArrayList<>();
for (String className : sequence) {
result.add(decompile(classSource.getClassHolder(className)));
final List<ClassNode> result = new ArrayList<>();
for (int i = 0; i < sequence.size(); ++i) {
final String className = sequence.get(i);
result.add(null);
final int index = i;
executor.execute(new Runnable() {
@Override public void run() {
Decompiler copy = new Decompiler(classSource, classLoader, executor);
result.set(index, copy.decompile(classSource.getClassHolder(className)));
}
});
}
executor.complete();
return result;
}

View File

@ -103,7 +103,7 @@ public class JavascriptBuilder {
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)));
executor.complete();
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses();
Decompiler decompiler = new Decompiler(classSet, classLoader);
Decompiler decompiler = new Decompiler(classSet, classLoader, executor);
ClassSetOptimizer optimizer = new ClassSetOptimizer(executor);
optimizer.optimizeAll(classSet);
executor.complete();
@ -143,7 +143,9 @@ public class JavascriptBuilder {
executor.execute(new Runnable() {
@Override public void run() {
RegisterAllocator allocator = new RegisterAllocator();
allocator.allocateRegisters(method);
Program program = ProgramUtils.copy(method.getProgram());
allocator.allocateRegisters(method, program);
method.setProgram(program);
}
});
}
@ -208,7 +210,7 @@ public class JavascriptBuilder {
writer.print("byte");
break;
case CHARACTER:
writer.print("character");
writer.print("char");
break;
case DOUBLE:
writer.print("double");

View File

@ -15,6 +15,7 @@
*/
package org.teavm.model;
import java.util.Collections;
import java.util.List;
/**
@ -22,18 +23,18 @@ import java.util.List;
* @author Alexey Andreev
*/
public class AnnotationValue {
private static final byte BOOLEAN = 0;
private static final byte BYTE = 1;
private static final byte SHORT = 2;
private static final byte INT = 3;
private static final byte LONG = 4;
private static final byte FLOAT = 5;
private static final byte DOUBLE = 6;
private static final byte STRING = 7;
private static final byte CLASS = 8;
private static final byte LIST = 9;
private static final byte ENUM = 10;
private static final byte ANNOTATION = 11;
public static final byte BOOLEAN = 0;
public static final byte BYTE = 1;
public static final byte SHORT = 2;
public static final byte INT = 3;
public static final byte LONG = 4;
public static final byte FLOAT = 5;
public static final byte DOUBLE = 6;
public static final byte STRING = 7;
public static final byte CLASS = 8;
public static final byte LIST = 9;
public static final byte ENUM = 10;
public static final byte ANNOTATION = 11;
private byte type;
private Object value;
@ -165,7 +166,7 @@ public class AnnotationValue {
if (type != LIST) {
throw new IllegalStateException("There is no List value");
}
return (List<AnnotationValue>)value;
return Collections.unmodifiableList((List<AnnotationValue>)value);
}
public FieldReference getEnumValue() {
@ -181,4 +182,8 @@ public class AnnotationValue {
}
return (AnnotationHolder)value;
}
public byte getType() {
return type;
}
}

View File

@ -0,0 +1,114 @@
/*
* 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.ArrayList;
import java.util.List;
import java.util.Map;
import org.teavm.common.Mapper;
import org.teavm.model.resource.MapperClassHolderSource;
import org.teavm.model.util.ProgramUtils;
/**
*
* @author Alexey Andreev
*/
public class CopyClassHolderSource implements ClassHolderSource {
private ClassHolderSource innerSource;
private MapperClassHolderSource mapperSource = new MapperClassHolderSource(new Mapper<String, ClassHolder>() {
@Override public ClassHolder map(String preimage) {
return copyClass(preimage);
}
});
public CopyClassHolderSource(ClassHolderSource innerSource) {
this.innerSource = innerSource;
}
@Override
public ClassHolder getClassHolder(String name) {
return mapperSource.getClassHolder(name);
}
private ClassHolder copyClass(String className) {
ClassHolder original = innerSource.getClassHolder(className);
if (original == null) {
return null;
}
ClassHolder copy = new ClassHolder(className);
copy.setLevel(original.getLevel());
copy.getModifiers().addAll(original.getModifiers());
copy.setParent(original.getParent());
copy.getInterfaces().addAll(original.getInterfaces());
for (MethodHolder method : original.getMethods()) {
copy.addMethod(copyMethod(method));
}
for (FieldHolder field : original.getFields()) {
copy.addField(copyField(field));
}
copyAnnotations(original.getAnnotations(), copy.getAnnotations());
return copy;
}
private MethodHolder copyMethod(MethodHolder method) {
MethodHolder copy = new MethodHolder(method.getDescriptor());
copy.setLevel(method.getLevel());
copy.getModifiers().addAll(method.getModifiers());
copy.setProgram(ProgramUtils.copy(method.getProgram()));
copyAnnotations(method.getAnnotations(), copy.getAnnotations());
return copy;
}
private FieldHolder copyField(FieldHolder field) {
FieldHolder copy = new FieldHolder(field.getName());
copy.setLevel(field.getLevel());
copy.getModifiers().addAll(field.getModifiers());
copy.setType(field.getType());
copy.setInitialValue(field.getInitialValue());
copyAnnotations(field.getAnnotations(), copy.getAnnotations());
return copy;
}
private void copyAnnotations(AnnotationContainer src, AnnotationContainer dst) {
for (AnnotationHolder annot : src.all()) {
dst.add(copyAnnotation(annot));
}
}
private AnnotationHolder copyAnnotation(AnnotationHolder annot) {
AnnotationHolder copy = new AnnotationHolder(annot.getType());
for (Map.Entry<String, AnnotationValue> entry : annot.getValues().entrySet()) {
copy.getValues().put(entry.getKey(), copyAnnotationValue(entry.getValue()));
}
return copy;
}
private AnnotationValue copyAnnotationValue(AnnotationValue value) {
switch (value.getType()) {
case AnnotationValue.LIST: {
List<AnnotationValue> listCopy = new ArrayList<>();
for (AnnotationValue item : value.getList()) {
listCopy.add(copyAnnotationValue(item));
}
return new AnnotationValue(listCopy);
}
case AnnotationValue.ANNOTATION:
return new AnnotationValue(copyAnnotation(value.getAnnotation()));
default:
return value;
}
}
}

View File

@ -48,10 +48,10 @@ public class ProgramUtils {
CopyVisitor insnCopier = new CopyVisitor();
insnCopier.programCopy = copy;
for (int i = 0; i < program.variableCount(); ++i) {
program.createVariable();
copy.createVariable();
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
program.createBasicBlock();
copy.createBasicBlock();
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
@ -346,7 +346,7 @@ public class ProgramUtils {
insnCopy.setMethod(insn.getMethod());
insnCopy.setType(insn.getType());
insnCopy.setInstance(insn.getInstance() != null ? copyVar(insn.getInstance()) : null);
insnCopy.setReceiver(copyVar(insn.getReceiver()));
insnCopy.setReceiver(insn.getReceiver() != null ? copyVar(insn.getReceiver()) : null);
for (Variable arg : insn.getArguments()) {
insnCopy.getArguments().add(copyVar(arg));
}

View File

@ -28,8 +28,7 @@ import org.teavm.model.instructions.JumpInstruction;
* @author Alexey Andreev
*/
public class RegisterAllocator {
public void allocateRegisters(MethodHolder method) {
Program program = method.getProgram();
public void allocateRegisters(MethodReader method, Program program) {
List<PhiArgumentCopy> phiArgsCopies = insertPhiArgumentsCopies(program);
InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
LivenessAnalyzer liveness = new LivenessAnalyzer();
@ -46,7 +45,7 @@ public class RegisterAllocator {
GraphColorer colorer = new GraphColorer();
colorer.colorize(interferenceGraph, classArray, colors);
for (int i = 0; i < colors.length; ++i) {
method.getProgram().variableAt(i).setRegister(colors[i]);
program.variableAt(i).setRegister(colors[i]);
}
}

View File

@ -21,21 +21,24 @@ import java.util.concurrent.Executor;
import org.teavm.model.ClassHolder;
import org.teavm.model.ListableClassHolderSource;
import org.teavm.model.MethodHolder;
import org.teavm.model.Program;
import org.teavm.model.util.ProgramUtils;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ClassSetOptimizer {
private List<MethodOptimization> optimizations = Arrays.<MethodOptimization>asList(
new CommonSubexpressionElimination(), new UnusedVariableElimination());
private Executor executor;
public ClassSetOptimizer(Executor executor) {
super();
this.executor = executor;
}
private List<MethodOptimization> getOptimizations() {
return Arrays.<MethodOptimization>asList(new CommonSubexpressionElimination(), new UnusedVariableElimination());
}
public void optimizeAll(ListableClassHolderSource classSource) {
for (String className : classSource.getClassNames()) {
ClassHolder cls = classSource.getClassHolder(className);
@ -44,9 +47,11 @@ public class ClassSetOptimizer {
executor.execute(new Runnable() {
@Override
public void run() {
for (MethodOptimization optimization : optimizations) {
optimization.optimize(method);
Program program = ProgramUtils.copy(method.getProgram());
for (MethodOptimization optimization : getOptimizations()) {
optimization.optimize(method, program);
}
method.setProgram(program);
}
});
}

View File

@ -42,10 +42,10 @@ public class CommonSubexpressionElimination implements MethodOptimization {
}
@Override
public void optimize(MethodHolder method) {
program = method.getProgram();
public void optimize(MethodReader method, Program program) {
this.program = program;
knownValues.clear();
Graph cfg = ProgramUtils.buildControlFlowGraph(method.getProgram());
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
domTree = GraphUtils.buildDominatorTree(cfg);
Graph dom = GraphUtils.buildDominatorGraph(domTree, cfg.size());
map = new int[program.variableCount()];

View File

@ -16,7 +16,7 @@
package org.teavm.optimization;
import org.teavm.model.BasicBlock;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReader;
import org.teavm.model.Program;
import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.util.BasicBlockMapper;
@ -27,8 +27,7 @@ import org.teavm.model.util.BasicBlockMapper;
*/
public class EmptyBlockElimination implements MethodOptimization {
@Override
public void optimize(MethodHolder method) {
final Program program = method.getProgram();
public void optimize(MethodReader method, final Program program) {
final int[] blockMapping = new int[program.basicBlockCount()];
for (int i = 0; i < blockMapping.length; ++i) {
blockMapping[i] = i;

View File

@ -15,12 +15,13 @@
*/
package org.teavm.optimization;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReader;
import org.teavm.model.Program;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface MethodOptimization {
void optimize(MethodHolder method);
void optimize(MethodReader method, Program program);
}

View File

@ -25,12 +25,12 @@ import org.teavm.model.instructions.*;
*/
public class UnusedVariableElimination implements MethodOptimization {
@Override
public void optimize(MethodHolder method) {
public void optimize(MethodReader method, Program program) {
if (method.getProgram() == null) {
return;
}
Graph graph = VariableUsageGraphBuilder.build(method.getProgram());
boolean[] escaping = VariableEscapeAnalyzer.findEscapingVariables(method.getProgram());
Graph graph = VariableUsageGraphBuilder.build(program);
boolean[] escaping = VariableEscapeAnalyzer.findEscapingVariables(program);
boolean[] used = new boolean[escaping.length];
int[] stack = new int[graph.size() * 2];
@ -54,7 +54,6 @@ public class UnusedVariableElimination implements MethodOptimization {
}
}
Program program = method.getProgram();
InstructionOptimizer insnOptimizer = new InstructionOptimizer(used);
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);

View File

@ -103,16 +103,16 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo {
public void execute() throws MojoExecutionException, MojoFailureException {
Runnable finalizer = null;
try {
ClassLoader classLoader = prepareClassLoader();
final ClassLoader classLoader = prepareClassLoader();
getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'");
findTestClasses(classLoader, testFiles, "");
Log log = getLog();
final Log log = getLog();
new File(outputDir, "tests").mkdirs();
resourceToFile("org/teavm/javascript/runtime.js", "runtime.js");
resourceToFile("org/teavm/maven/junit-support.js", "junit-support.js");
resourceToFile("org/teavm/maven/junit.css", "junit.css");
resourceToFile("org/teavm/maven/junit.html", "junit.html");
ClassHolderSource classSource = new ClasspathClassHolderSource(classLoader);
final ClassHolderSource classSource = new ClasspathClassHolderSource(classLoader);
for (String testClass : testClasses) {
ClassHolder classHolder = classSource.getClassHolder(testClass);
if (classHolder == null) {
@ -169,12 +169,22 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo {
};
executor = threadedExecutor;
}
for (MethodReference method : testMethods) {
log.debug("Building test for " + method);
decompileClassesForTest(classLoader, method, fileNames.get(method), executor);
for (final MethodReference method : testMethods) {
executor.execute(new Runnable() {
@Override public void run() {
log.debug("Building test for " + method);
try {
decompileClassesForTest(classLoader, new CopyClassHolderSource(classSource), method,
fileNames.get(method), new SimpleFiniteExecutor());
} catch (IOException e) {
log.error("Error generating JavaScript", e);
}
}
});
++methodsGenerated;
}
log.info("Test files successfully generated for " + methodsGenerated + " method(s)");
executor.complete();
log.info("Test files successfully generated for " + methodsGenerated + " method(s).");
} catch (IOException e) {
throw new MojoFailureException("IO error occured generating JavaScript files", e);
} finally {
@ -216,11 +226,11 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo {
}
}
private void decompileClassesForTest(ClassLoader classLoader, MethodReference methodRef, String targetName,
FiniteExecutor executor) throws IOException {
private void decompileClassesForTest(ClassLoader classLoader, ClassHolderSource classSource,
MethodReference methodRef, String targetName, FiniteExecutor executor) throws IOException {
JavascriptBuilderFactory builderFactory = new JavascriptBuilderFactory();
builderFactory.setClassLoader(classLoader);
builderFactory.setClassSource(new ClasspathClassHolderSource(classLoader));
builderFactory.setClassSource(classSource);
builderFactory.setExecutor(executor);
JavascriptBuilder builder = builderFactory.create();
builder.setMinifying(minifying);

View File

@ -47,7 +47,7 @@
<minifying>false</minifying>
<mainClass>org.teavm.samples.HelloWorld</mainClass>
<mainPageIncluded>true</mainPageIncluded>
<bytecodeLogging>true</bytecodeLogging>
<bytecodeLogging>false</bytecodeLogging>
</configuration>
</execution>
</executions>