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