diff --git a/teavm-classlib/pom.xml b/teavm-classlib/pom.xml
index 9f638f16a..76ebea08d 100644
--- a/teavm-classlib/pom.xml
+++ b/teavm-classlib/pom.xml
@@ -53,7 +53,7 @@
process-test-classes
false
- 1
+ 0
diff --git a/teavm-core/src/main/java/org/teavm/common/ThreadPoolFiniteExecutor.java b/teavm-core/src/main/java/org/teavm/common/ThreadPoolFiniteExecutor.java
index 455915e8c..3eebaea3e 100644
--- a/teavm-core/src/main/java/org/teavm/common/ThreadPoolFiniteExecutor.java
+++ b/teavm-core/src/main/java/org/teavm/common/ThreadPoolFiniteExecutor.java
@@ -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;
+ }
}
}
}
diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
index 9bd265369..220b395d2 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
@@ -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 result = new ArrayList<>();
- for (String className : sequence) {
- result.add(decompile(classSource.getClassHolder(className)));
+ final List 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;
}
diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java
index f033ab6e3..a587eb441 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java
@@ -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");
diff --git a/teavm-core/src/main/java/org/teavm/model/AnnotationValue.java b/teavm-core/src/main/java/org/teavm/model/AnnotationValue.java
index 5b775ac76..3efcf9d89 100644
--- a/teavm-core/src/main/java/org/teavm/model/AnnotationValue.java
+++ b/teavm-core/src/main/java/org/teavm/model/AnnotationValue.java
@@ -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)value;
+ return Collections.unmodifiableList((List)value);
}
public FieldReference getEnumValue() {
@@ -181,4 +182,8 @@ public class AnnotationValue {
}
return (AnnotationHolder)value;
}
+
+ public byte getType() {
+ return type;
+ }
}
diff --git a/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java b/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java
new file mode 100644
index 000000000..9e90744c2
--- /dev/null
+++ b/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java
@@ -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() {
+ @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 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 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;
+ }
+ }
+}
diff --git a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java
index fa6c8fe32..77a64e668 100644
--- a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java
+++ b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java
@@ -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));
}
diff --git a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java
index b45d5c002..59c54a43e 100644
--- a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java
+++ b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java
@@ -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 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]);
}
}
diff --git a/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java b/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java
index 8c30e4ca0..9e24f48a0 100644
--- a/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java
+++ b/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java
@@ -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
*/
public class ClassSetOptimizer {
- private List optimizations = Arrays.asList(
- new CommonSubexpressionElimination(), new UnusedVariableElimination());
private Executor executor;
public ClassSetOptimizer(Executor executor) {
- super();
this.executor = executor;
}
+ private List getOptimizations() {
+ return Arrays.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);
}
});
}
diff --git a/teavm-core/src/main/java/org/teavm/optimization/CommonSubexpressionElimination.java b/teavm-core/src/main/java/org/teavm/optimization/CommonSubexpressionElimination.java
index e1932caf5..916854413 100644
--- a/teavm-core/src/main/java/org/teavm/optimization/CommonSubexpressionElimination.java
+++ b/teavm-core/src/main/java/org/teavm/optimization/CommonSubexpressionElimination.java
@@ -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()];
diff --git a/teavm-core/src/main/java/org/teavm/optimization/EmptyBlockElimination.java b/teavm-core/src/main/java/org/teavm/optimization/EmptyBlockElimination.java
index 24cd7656e..cfc616bb1 100644
--- a/teavm-core/src/main/java/org/teavm/optimization/EmptyBlockElimination.java
+++ b/teavm-core/src/main/java/org/teavm/optimization/EmptyBlockElimination.java
@@ -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;
diff --git a/teavm-core/src/main/java/org/teavm/optimization/MethodOptimization.java b/teavm-core/src/main/java/org/teavm/optimization/MethodOptimization.java
index 425a444f9..6d1528ace 100644
--- a/teavm-core/src/main/java/org/teavm/optimization/MethodOptimization.java
+++ b/teavm-core/src/main/java/org/teavm/optimization/MethodOptimization.java
@@ -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
*/
public interface MethodOptimization {
- void optimize(MethodHolder method);
+ void optimize(MethodReader method, Program program);
}
diff --git a/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java b/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java
index c8198fa69..f0b49e3cc 100644
--- a/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java
+++ b/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java
@@ -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);
diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java
index 8f584f058..aa5263df3 100644
--- a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java
+++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java
@@ -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);
diff --git a/teavm-samples/pom.xml b/teavm-samples/pom.xml
index f00911da4..3abc6a52d 100644
--- a/teavm-samples/pom.xml
+++ b/teavm-samples/pom.xml
@@ -47,7 +47,7 @@
false
org.teavm.samples.HelloWorld
true
- true
+ false