mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-12-03 01:50:07 +08:00
Support of multithreaded execution. Performance optimizations.
This commit is contained in:
parent
0c240f5636
commit
24921c6e80
@ -53,7 +53,7 @@
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<minifying>false</minifying>
|
||||
<numThreads>1</numThreads>
|
||||
<numThreads>0</numThreads>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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()];
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user