diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index e314c2d96..71c0970da 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -15,19 +15,19 @@ */ package org.teavm.classlib.impl; -import org.teavm.javascript.JavascriptBuilderHost; -import org.teavm.javascript.JavascriptBuilderPlugin; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; +import org.teavm.vm.spi.TeaVMHost; +import org.teavm.vm.spi.TeaVMPlugin; /** * * @author Alexey Andreev */ -public class JCLPlugin implements JavascriptBuilderPlugin { +public class JCLPlugin implements TeaVMPlugin { @Override - public void install(JavascriptBuilderHost host) { + public void install(TeaVMHost host) { host.add(new EnumDependencySupport()); host.add(new EnumTransformer()); host.add(new ClassLookupDependencySupport()); diff --git a/teavm-classlib/src/main/resources/META-INF/services/org.teavm.javascript.JavascriptBuilderPlugin b/teavm-classlib/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin similarity index 100% rename from teavm-classlib/src/main/resources/META-INF/services/org.teavm.javascript.JavascriptBuilderPlugin rename to teavm-classlib/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index 4914f43a9..682a30384 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -33,7 +33,7 @@ import org.teavm.model.*; * * @author Alexey Andreev */ -public class Renderer implements ExprVisitor, StatementVisitor { +public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext { private static final String variableNames = "abcdefghijkmnopqrstuvwxyz"; private NamingStrategy naming; private SourceWriter writer; @@ -57,14 +57,17 @@ public class Renderer implements ExprVisitor, StatementVisitor { this.classLoader = classLoader; } + @Override public SourceWriter getWriter() { return writer; } + @Override public NamingStrategy getNaming() { return naming; } + @Override public boolean isMinifying() { return minifying; } @@ -73,6 +76,16 @@ public class Renderer implements ExprVisitor, StatementVisitor { this.minifying = minifying; } + @Override + public ListableClassHolderSource getClassSource() { + return classSource; + } + + @Override + public ClassLoader getClassLoader() { + return classLoader; + } + public void renderRuntime() throws RenderingException { try { renderRuntimeCls(); diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptResourceRenderer.java b/teavm-core/src/main/java/org/teavm/javascript/RenderingContext.java similarity index 62% rename from teavm-core/src/main/java/org/teavm/javascript/JavascriptResourceRenderer.java rename to teavm-core/src/main/java/org/teavm/javascript/RenderingContext.java index 2bc6d5be2..2b15f5684 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptResourceRenderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/RenderingContext.java @@ -15,12 +15,22 @@ */ package org.teavm.javascript; -import java.io.IOException; +import org.teavm.codegen.NamingStrategy; +import org.teavm.codegen.SourceWriter; +import org.teavm.model.ListableClassReaderSource; /** * - * @author Alexey Andreev + * @author Alexey Andreev */ -public interface JavascriptResourceRenderer { - void render(JavascriptBuildTarget buildTarget) throws IOException; +public interface RenderingContext { + NamingStrategy getNaming(); + + SourceWriter getWriter(); + + boolean isMinifying(); + + ListableClassReaderSource getClassSource(); + + ClassLoader getClassLoader(); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuildTarget.java b/teavm-core/src/main/java/org/teavm/vm/BuildTarget.java similarity index 91% rename from teavm-core/src/main/java/org/teavm/javascript/JavascriptBuildTarget.java rename to teavm-core/src/main/java/org/teavm/vm/BuildTarget.java index d6c787c71..928dc3243 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuildTarget.java +++ b/teavm-core/src/main/java/org/teavm/vm/BuildTarget.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.javascript; +package org.teavm.vm; import java.io.IOException; import java.io.OutputStream; @@ -22,6 +22,6 @@ import java.io.OutputStream; * * @author Alexey Andreev */ -public interface JavascriptBuildTarget { +public interface BuildTarget { OutputStream createResource(String fileName) throws IOException; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/DirectoryBuildTarget.java b/teavm-core/src/main/java/org/teavm/vm/DirectoryBuildTarget.java similarity index 91% rename from teavm-core/src/main/java/org/teavm/javascript/DirectoryBuildTarget.java rename to teavm-core/src/main/java/org/teavm/vm/DirectoryBuildTarget.java index bfbd376b2..a7e6db74b 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/DirectoryBuildTarget.java +++ b/teavm-core/src/main/java/org/teavm/vm/DirectoryBuildTarget.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.javascript; +package org.teavm.vm; import java.io.File; import java.io.FileOutputStream; @@ -24,7 +24,7 @@ import java.io.OutputStream; * * @author Alexey Andreev */ -public class DirectoryBuildTarget implements JavascriptBuildTarget { +public class DirectoryBuildTarget implements BuildTarget { private File directory; public DirectoryBuildTarget(File directory) { diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptProcessedClassSource.java b/teavm-core/src/main/java/org/teavm/vm/JavascriptProcessedClassSource.java similarity index 98% rename from teavm-core/src/main/java/org/teavm/javascript/JavascriptProcessedClassSource.java rename to teavm-core/src/main/java/org/teavm/vm/JavascriptProcessedClassSource.java index f3729f559..b54e56ed3 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptProcessedClassSource.java +++ b/teavm-core/src/main/java/org/teavm/vm/JavascriptProcessedClassSource.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.javascript; +package org.teavm.vm; import java.util.ArrayList; import java.util.List; diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java similarity index 84% rename from teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java rename to teavm-core/src/main/java/org/teavm/vm/TeaVM.java index b888aef5e..f10824d88 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.javascript; +package org.teavm.vm; import java.io.*; import java.util.*; import org.teavm.codegen.*; import org.teavm.common.FiniteExecutor; import org.teavm.dependency.*; +import org.teavm.javascript.*; import org.teavm.javascript.ast.ClassNode; import org.teavm.javascript.ni.Generator; import org.teavm.model.*; @@ -28,12 +29,15 @@ import org.teavm.model.util.ProgramUtils; import org.teavm.model.util.RegisterAllocator; import org.teavm.optimization.ClassSetOptimizer; import org.teavm.optimization.Devirtualization; +import org.teavm.vm.spi.RendererListener; +import org.teavm.vm.spi.TeaVMHost; +import org.teavm.vm.spi.TeaVMPlugin; /** * * @author Alexey Andreev */ -public class JavascriptBuilder implements JavascriptBuilderHost { +public class TeaVM implements TeaVMHost { private JavascriptProcessedClassSource classSource; private DependencyChecker dependencyChecker; private FiniteExecutor executor; @@ -41,12 +45,13 @@ public class JavascriptBuilder implements JavascriptBuilderHost { private boolean minifying = true; private boolean bytecodeLogging; private OutputStream logStream = System.out; - private Map entryPoints = new HashMap<>(); + private Map entryPoints = new HashMap<>(); private Map exportedClasses = new HashMap<>(); - private List ressourceRenderers = new ArrayList<>(); private Map methodGenerators = new HashMap<>(); + private List rendererListeners = new ArrayList<>(); + private Properties properties = new Properties(); - JavascriptBuilder(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) { + TeaVM(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) { this.classSource = new JavascriptProcessedClassSource(classSource); this.classLoader = classLoader; dependencyChecker = new DependencyChecker(this.classSource, classLoader, executor); @@ -63,16 +68,17 @@ public class JavascriptBuilder implements JavascriptBuilderHost { classSource.addTransformer(transformer); } - @Override - public void add(JavascriptResourceRenderer resourceRenderer) { - ressourceRenderers.add(resourceRenderer); - } @Override public void add(MethodReference methodRef, Generator generator) { methodGenerators.put(methodRef, generator); } + @Override + public void add(RendererListener listener) { + rendererListeners.add(listener); + } + @Override public ClassLoader getClassLoader() { return classLoader; @@ -94,18 +100,37 @@ public class JavascriptBuilder implements JavascriptBuilderHost { this.bytecodeLogging = bytecodeLogging; } - public JavascriptEntryPoint entryPoint(String name, MethodReference ref) { + public void setProperties(Properties properties) { + this.properties.clear(); + if (properties != null) { + this.properties.putAll(properties); + } + } + + @Override + public Properties getProperties() { + return new Properties(properties); + } + + public TeaVMEntryPoint entryPoint(String name, MethodReference ref) { if (entryPoints.containsKey(name)) { throw new IllegalArgumentException("Entry point with public name `" + name + "' already defined " + "for method " + ref); } - JavascriptEntryPoint entryPoint = new JavascriptEntryPoint(name, ref, + TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref, dependencyChecker.linkMethod(ref, DependencyStack.ROOT)); dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT); entryPoints.put(name, entryPoint); return entryPoint; } + public TeaVMEntryPoint linkMethod(MethodReference ref) { + TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref, + dependencyChecker.linkMethod(ref, DependencyStack.ROOT)); + dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT); + return entryPoint; + } + public void exportType(String name, String className) { if (exportedClasses.containsKey(name)) { throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class " + @@ -115,6 +140,10 @@ public class JavascriptBuilder implements JavascriptBuilderHost { exportedClasses.put(name, className); } + public void linkType(String className) { + dependencyChecker.initClass(className, DependencyStack.ROOT); + } + public ClassHolderSource getClassSource() { return classSource; } @@ -135,7 +164,7 @@ public class JavascriptBuilder implements JavascriptBuilderHost { dependencyChecker.checkForMissingItems(); } - public void build(Appendable writer, JavascriptBuildTarget target) throws RenderingException { + public void build(Appendable writer, BuildTarget target) throws RenderingException { AliasProvider aliasProvider = minifying ? new MinifyingAliasProvider() : new DefaultAliasProvider(); DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, classSource); naming.setMinifying(minifying); @@ -174,17 +203,27 @@ public class JavascriptBuilder implements JavascriptBuilderHost { // Just don't do anything } } - Renderer renderer = new Renderer(sourceWriter, classSet, classLoader); - renderer.renderRuntime(); for (Map.Entry entry : methodGenerators.entrySet()) { decompiler.addGenerator(entry.getKey(), entry.getValue()); } List clsNodes = decompiler.decompile(classSet.getClassNames()); - for (ClassNode clsNode : clsNodes) { - renderer.render(clsNode); - } + Renderer renderer = new Renderer(sourceWriter, classSet, classLoader); try { - for (Map.Entry entry : entryPoints.entrySet()) { + for (RendererListener listener : rendererListeners) { + listener.begin(renderer, target); + } + renderer.renderRuntime(); + for (ClassNode clsNode : clsNodes) { + ClassReader cls = classSet.get(clsNode.getName()); + for (RendererListener listener : rendererListeners) { + listener.beforeClass(cls); + } + renderer.render(clsNode); + for (RendererListener listener : rendererListeners) { + listener.afterClass(cls); + } + } + for (Map.Entry entry : entryPoints.entrySet()) { sourceWriter.append(entry.getKey()).ws().append("=").ws().appendMethodBody(entry.getValue().reference) .append(";").softNewLine(); } @@ -192,8 +231,8 @@ public class JavascriptBuilder implements JavascriptBuilderHost { sourceWriter.append(entry.getKey()).ws().append("=").ws().appendClass(entry.getValue()).append(";") .softNewLine(); } - for (JavascriptResourceRenderer resourceRenderer : ressourceRenderers) { - resourceRenderer.render(target); + for (RendererListener listener : rendererListeners) { + listener.complete(); } } catch (IOException e) { throw new RenderingException("IO Error occured", e); @@ -350,7 +389,7 @@ public class JavascriptBuilder implements JavascriptBuilderHost { } public void installPlugins() { - for (JavascriptBuilderPlugin plugin : ServiceLoader.load(JavascriptBuilderPlugin.class, classLoader)) { + for (TeaVMPlugin plugin : ServiceLoader.load(TeaVMPlugin.class, classLoader)) { plugin.install(this); } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilderFactory.java b/teavm-core/src/main/java/org/teavm/vm/TeaVMBuilder.java similarity index 76% rename from teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilderFactory.java rename to teavm-core/src/main/java/org/teavm/vm/TeaVMBuilder.java index 98f59399b..d70ac2f2e 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilderFactory.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVMBuilder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.javascript; +package org.teavm.vm; import org.teavm.common.FiniteExecutor; import org.teavm.common.SimpleFiniteExecutor; @@ -23,7 +23,7 @@ import org.teavm.model.ClassHolderSource; * * @author Alexey Andreev */ -public class JavascriptBuilderFactory { +public class TeaVMBuilder { ClassHolderSource classSource; ClassLoader classLoader; FiniteExecutor executor = new SimpleFiniteExecutor(); @@ -32,27 +32,30 @@ public class JavascriptBuilderFactory { return classSource; } - public void setClassSource(ClassHolderSource classSource) { + public TeaVMBuilder setClassSource(ClassHolderSource classSource) { this.classSource = classSource; + return this; } public ClassLoader getClassLoader() { return classLoader; } - public void setClassLoader(ClassLoader classLoader) { + public TeaVMBuilder setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; + return this; } public FiniteExecutor getExecutor() { return executor; } - public void setExecutor(FiniteExecutor executor) { + public TeaVMBuilder setExecutor(FiniteExecutor executor) { this.executor = executor; + return this; } - public JavascriptBuilder create() { - return new JavascriptBuilder(classSource, classLoader, executor); + public TeaVM build() { + return new TeaVM(classSource, classLoader, executor); } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptEntryPoint.java b/teavm-core/src/main/java/org/teavm/vm/TeaVMEntryPoint.java similarity index 84% rename from teavm-core/src/main/java/org/teavm/javascript/JavascriptEntryPoint.java rename to teavm-core/src/main/java/org/teavm/vm/TeaVMEntryPoint.java index f4e6f19ce..4f27c7e56 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptEntryPoint.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVMEntryPoint.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.javascript; +package org.teavm.vm; import org.teavm.dependency.MethodDependency; import org.teavm.model.MethodReference; @@ -22,12 +22,12 @@ import org.teavm.model.MethodReference; * * @author Alexey Andreev */ -public class JavascriptEntryPoint { +public class TeaVMEntryPoint { private String publicName; MethodReference reference; private MethodDependency method; - JavascriptEntryPoint(String publicName, MethodReference reference, MethodDependency method) { + TeaVMEntryPoint(String publicName, MethodReference reference, MethodDependency method) { this.publicName = publicName; this.reference = reference; this.method = method; @@ -38,7 +38,7 @@ public class JavascriptEntryPoint { return publicName; } - public JavascriptEntryPoint withValue(int argument, String type) { + public TeaVMEntryPoint withValue(int argument, String type) { if (argument > reference.parameterCount()) { throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount()); } diff --git a/teavm-core/src/main/java/org/teavm/vm/spi/AbstractRendererListener.java b/teavm-core/src/main/java/org/teavm/vm/spi/AbstractRendererListener.java new file mode 100644 index 000000000..393d45292 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/vm/spi/AbstractRendererListener.java @@ -0,0 +1,43 @@ +/* + * 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.vm.spi; + +import java.io.IOException; +import org.teavm.javascript.RenderingContext; +import org.teavm.model.ClassReader; +import org.teavm.vm.BuildTarget; + +/** + * + * @author Alexey Andreev + */ +public abstract class AbstractRendererListener implements RendererListener { + @Override + public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { + } + + @Override + public void beforeClass(ClassReader cls) throws IOException { + } + + @Override + public void afterClass(ClassReader cls) throws IOException { + } + + @Override + public void complete() throws IOException { + } +} diff --git a/teavm-core/src/main/java/org/teavm/vm/spi/RendererListener.java b/teavm-core/src/main/java/org/teavm/vm/spi/RendererListener.java new file mode 100644 index 000000000..f7c04d4ac --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/vm/spi/RendererListener.java @@ -0,0 +1,35 @@ +/* + * 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.vm.spi; + +import java.io.IOException; +import org.teavm.javascript.RenderingContext; +import org.teavm.model.ClassReader; +import org.teavm.vm.BuildTarget; + +/** + * + * @author Alexey Andreev + */ +public interface RendererListener { + void begin(RenderingContext context, BuildTarget buildTarget) throws IOException; + + void beforeClass(ClassReader cls) throws IOException; + + void afterClass(ClassReader cls) throws IOException; + + void complete() throws IOException; +} diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilderHost.java b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java similarity index 86% rename from teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilderHost.java rename to teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java index fd417a0cf..68fc73314 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilderHost.java +++ b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.javascript; +package org.teavm.vm.spi; +import java.util.Properties; import org.teavm.dependency.DependencyListener; import org.teavm.javascript.ni.Generator; import org.teavm.model.ClassHolderTransformer; @@ -24,14 +25,16 @@ import org.teavm.model.MethodReference; * * @author Alexey Andreev */ -public interface JavascriptBuilderHost { +public interface TeaVMHost { void add(DependencyListener dependencyListener); void add(ClassHolderTransformer classTransformer); - void add(JavascriptResourceRenderer resourceRenderer); - void add(MethodReference methodRef, Generator generator); + void add(RendererListener listener); + ClassLoader getClassLoader(); + + Properties getProperties(); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilderPlugin.java b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMPlugin.java similarity index 84% rename from teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilderPlugin.java rename to teavm-core/src/main/java/org/teavm/vm/spi/TeaVMPlugin.java index 8b1dd1672..63c1e61ba 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilderPlugin.java +++ b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMPlugin.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.javascript; +package org.teavm.vm.spi; /** * * @author Alexey Andreev */ -public interface JavascriptBuilderPlugin { - void install(JavascriptBuilderHost host); +public interface TeaVMPlugin { + void install(TeaVMHost host); } diff --git a/teavm-html4j/pom.xml b/teavm-html4j/pom.xml index 8bd267988..fa69043b5 100644 --- a/teavm-html4j/pom.xml +++ b/teavm-html4j/pom.xml @@ -99,9 +99,6 @@ org.teavm.javascript.NullPointerExceptionTransformer - - org/netbeans/html/ko4j/knockout-2.2.1.js - diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/EntryPointGenerator.java b/teavm-html4j/src/main/java/org/teavm/html4j/EntryPointGenerator.java new file mode 100644 index 000000000..123fb9d4f --- /dev/null +++ b/teavm-html4j/src/main/java/org/teavm/html4j/EntryPointGenerator.java @@ -0,0 +1,87 @@ +/* + * 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.html4j; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.teavm.codegen.SourceWriter; +import org.teavm.dependency.*; +import org.teavm.javascript.Renderer; +import org.teavm.javascript.RenderingContext; +import org.teavm.vm.BuildTarget; +import org.teavm.vm.spi.AbstractRendererListener; + +/** + * + * @author Alexey Andreev + */ +public class EntryPointGenerator extends AbstractRendererListener implements DependencyListener { + private List classesToLoad = new ArrayList<>(); + private SourceWriter writer; + + public EntryPointGenerator(String classesToLoad) { + for (String className : classesToLoad.split(",| |;")) { + className = className.trim(); + if (!className.isEmpty()) { + this.classesToLoad.add(className); + } + } + } + + @Override + public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { + writer = context.getWriter(); + } + + @Override + public void complete() throws IOException { + if (classesToLoad.isEmpty()) { + return; + } + writer.append("function VM() {").softNewLine(); + writer.append("}").newLine(); + writer.append("VM.prototype.loadClass = function(className) {").softNewLine().indent(); + writer.append("switch (className) {").indent().softNewLine(); + for (String className : classesToLoad) { + writer.append("case \"").append(Renderer.escapeString(className)).append("\": "); + writer.appendClass(className).append(".$clinit(); break;").softNewLine(); + } + writer.append("default: throw \"Can't load class \" + className;").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.outdent().append("}").newLine(); + writer.append("function bck2brwsr() { return new VM(); }").newLine(); + } + + @Override + public void started(DependencyChecker dependencyChecker) { + for (String className : classesToLoad) { + dependencyChecker.initClass(className, DependencyStack.ROOT); + } + } + + @Override + public void classAchieved(DependencyChecker dependencyChecker, String className) { + } + + @Override + public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) { + } + + @Override + public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) { + } +} diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/HTML4JPlugin.java b/teavm-html4j/src/main/java/org/teavm/html4j/HTML4JPlugin.java index 8674bc0f8..b41ddba88 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/HTML4JPlugin.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/HTML4JPlugin.java @@ -15,18 +15,25 @@ */ package org.teavm.html4j; -import org.teavm.javascript.JavascriptBuilderHost; -import org.teavm.javascript.JavascriptBuilderPlugin; +import org.teavm.dependency.DependencyListener; +import org.teavm.vm.spi.RendererListener; +import org.teavm.vm.spi.TeaVMHost; +import org.teavm.vm.spi.TeaVMPlugin; /** * * @author Alexey Andreev */ -public class HTML4JPlugin implements JavascriptBuilderPlugin { +public class HTML4JPlugin implements TeaVMPlugin { @Override - public void install(JavascriptBuilderHost host) { + public void install(TeaVMHost host) { host.add(new JavaScriptBodyDependency()); host.add(new JavaScriptBodyTransformer()); host.add(new JCLHacks()); + host.add(new JavaScriptResourceInterceptor()); + EntryPointGenerator entryPointGen = new EntryPointGenerator(host.getProperties() + .getProperty("html4j.entryPoints", "")); + host.add((DependencyListener)entryPointGen); + host.add((RendererListener)entryPointGen); } } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptResourceInterceptor.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptResourceInterceptor.java new file mode 100644 index 000000000..561bba643 --- /dev/null +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptResourceInterceptor.java @@ -0,0 +1,65 @@ +/* + * 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.html4j; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import net.java.html.js.JavaScriptResource; +import org.apache.commons.io.IOUtils; +import org.teavm.javascript.RenderingContext; +import org.teavm.javascript.RenderingException; +import org.teavm.model.AnnotationReader; +import org.teavm.model.ClassReader; +import org.teavm.vm.BuildTarget; +import org.teavm.vm.spi.AbstractRendererListener; + +/** + * + * @author Alexey Andreev + */ +public class JavaScriptResourceInterceptor extends AbstractRendererListener { + @Override + public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { + boolean hasOneResource = false; + for (String className : context.getClassSource().getClassNames()) { + ClassReader cls = context.getClassSource().get(className); + AnnotationReader annot = cls.getAnnotations().get(JavaScriptResource.class.getName()); + if (annot == null) { + continue; + } + String path = annot.getValue("value").getString(); + String packageName = className.substring(0, className.lastIndexOf('.')); + String resourceName = packageName.replace('.', '/') + "/" + path; + try (InputStream input = context.getClassLoader().getResourceAsStream(resourceName)) { + if (input == null) { + throw new RenderingException("Error processing JavaScriptResource annotation on class " + + className + ". Resource not found: " + resourceName); + } + @SuppressWarnings("resource") + StringWriter writer = new StringWriter(); + IOUtils.copy(input, writer); + writer.close(); + context.getWriter().append("// Resource " + path + " included by " + className).newLine(); + context.getWriter().append(writer.toString()).newLine().newLine(); + } + hasOneResource = true; + } + if (hasOneResource) { + context.getWriter().append("// TeaVM generated classes").newLine(); + } + } +} diff --git a/teavm-html4j/src/main/resources/META-INF/services/org.teavm.javascript.JavascriptBuilderPlugin b/teavm-html4j/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin similarity index 100% rename from teavm-html4j/src/main/resources/META-INF/services/org.teavm.javascript.JavascriptBuilderPlugin rename to teavm-html4j/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin diff --git a/teavm-jso/src/main/java/org/teavm/javascript/ni/plugin/JSObjectBuilderPlugin.java b/teavm-jso/src/main/java/org/teavm/javascript/ni/plugin/JSObjectBuilderPlugin.java index 2e67e26d0..b98a72b35 100644 --- a/teavm-jso/src/main/java/org/teavm/javascript/ni/plugin/JSObjectBuilderPlugin.java +++ b/teavm-jso/src/main/java/org/teavm/javascript/ni/plugin/JSObjectBuilderPlugin.java @@ -15,16 +15,16 @@ */ package org.teavm.javascript.ni.plugin; -import org.teavm.javascript.JavascriptBuilderHost; -import org.teavm.javascript.JavascriptBuilderPlugin; +import org.teavm.vm.spi.TeaVMHost; +import org.teavm.vm.spi.TeaVMPlugin; /** * * @author Alexey Andreev */ -public class JSObjectBuilderPlugin implements JavascriptBuilderPlugin { +public class JSObjectBuilderPlugin implements TeaVMPlugin { @Override - public void install(JavascriptBuilderHost host) { + public void install(TeaVMHost host) { host.add(new JSObjectClassTransformer()); } } diff --git a/teavm-jso/src/main/resources/META-INF/services/org.teavm.javascript.JavascriptBuilderPlugin b/teavm-jso/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin similarity index 100% rename from teavm-jso/src/main/resources/META-INF/services/org.teavm.javascript.JavascriptBuilderPlugin rename to teavm-jso/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java index 5c2892d36..7f3def9c7 100644 --- a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java +++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java @@ -33,14 +33,17 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.teavm.common.ThreadPoolFiniteExecutor; -import org.teavm.javascript.DirectoryBuildTarget; -import org.teavm.javascript.JavascriptBuilder; -import org.teavm.javascript.JavascriptBuilderFactory; +import org.teavm.javascript.RenderingContext; import org.teavm.model.ClassHolderTransformer; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; import org.teavm.parsing.ClasspathClassHolderSource; +import org.teavm.vm.BuildTarget; +import org.teavm.vm.DirectoryBuildTarget; +import org.teavm.vm.TeaVM; +import org.teavm.vm.TeaVMBuilder; +import org.teavm.vm.spi.AbstractRendererListener; /** * @@ -61,6 +64,7 @@ public class BuildJavascriptMojo extends AbstractMojo { @Parameter(defaultValue = "${project.build.outputDirectory}") private File classFiles; + @Parameter private String targetFileName = "classes.js"; @Parameter @@ -72,6 +76,9 @@ public class BuildJavascriptMojo extends AbstractMojo { @Parameter private RuntimeCopyOperation runtime = RuntimeCopyOperation.SEPARATE; + @Parameter + private Properties properties; + @Parameter private boolean mainPageIncluded; @@ -92,6 +99,10 @@ public class BuildJavascriptMojo extends AbstractMojo { this.targetDirectory = targetDirectory; } + public void setTargetFileName(String targetFileName) { + this.targetFileName = targetFileName; + } + public void setClassFiles(File classFiles) { this.classFiles = classFiles; } @@ -124,6 +135,10 @@ public class BuildJavascriptMojo extends AbstractMojo { this.transformers = transformers; } + public void setProperties(Properties properties) { + this.properties = properties; + } + @Override public void execute() throws MojoExecutionException { Log log = getLog(); @@ -131,9 +146,8 @@ public class BuildJavascriptMojo extends AbstractMojo { try { ClassLoader classLoader = prepareClassLoader(); log.info("Building JavaScript file"); - JavascriptBuilderFactory builderFactory = new JavascriptBuilderFactory(); - builderFactory.setClassLoader(classLoader); - builderFactory.setClassSource(new ClasspathClassHolderSource(classLoader)); + TeaVMBuilder vmBuilder = new TeaVMBuilder(); + vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader)); if (numThreads != 1) { int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors(); final ThreadPoolFiniteExecutor executor = new ThreadPoolFiniteExecutor(threads); @@ -142,28 +156,30 @@ public class BuildJavascriptMojo extends AbstractMojo { executor.stop(); } }; - builderFactory.setExecutor(executor); + vmBuilder.setExecutor(executor); } - JavascriptBuilder builder = builderFactory.create(); - builder.setMinifying(minifying); - builder.setBytecodeLogging(bytecodeLogging); - builder.installPlugins(); + TeaVM vm = vmBuilder.build(); + vm.setMinifying(minifying); + vm.setBytecodeLogging(bytecodeLogging); + vm.setProperties(properties); + vm.installPlugins(); for (ClassHolderTransformer transformer : instantiateTransformers(classLoader)) { - builder.add(transformer); + vm.add(transformer); + } + vm.prepare(); + if (mainClass != null) { + MethodDescriptor mainMethodDesc = new MethodDescriptor("main", ValueType.arrayOf( + ValueType.object("java.lang.String")), ValueType.VOID); + vm.entryPoint("main", new MethodReference(mainClass, mainMethodDesc)) + .withValue(1, "java.lang.String"); } - builder.prepare(); - MethodDescriptor mainMethodDesc = new MethodDescriptor("main", ValueType.arrayOf( - ValueType.object("java.lang.String")), ValueType.VOID); - builder.entryPoint("main", new MethodReference(mainClass, mainMethodDesc)) - .withValue(1, "java.lang.String"); targetDirectory.mkdirs(); try (FileWriter writer = new FileWriter(new File(targetDirectory, targetFileName))) { if (runtime == RuntimeCopyOperation.MERGED) { - resourceToWriter("org/teavm/javascript/runtime.js", writer); - writer.append("\n"); + vm.add(runtimeInjector); } - builder.build(writer, new DirectoryBuildTarget(targetDirectory)); - builder.checkForMissingItems(); + vm.build(writer, new DirectoryBuildTarget(targetDirectory)); + vm.checkForMissingItems(); log.info("JavaScript file successfully built"); } if (runtime == RuntimeCopyOperation.SEPARATE) { @@ -191,6 +207,17 @@ public class BuildJavascriptMojo extends AbstractMojo { } } + private AbstractRendererListener runtimeInjector = new AbstractRendererListener() { + @Override + public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { + @SuppressWarnings("resource") + StringWriter writer = new StringWriter(); + resourceToWriter("org/teavm/javascript/runtime.js", writer); + writer.close(); + context.getWriter().append(writer.toString()).newLine(); + } + }; + private List instantiateTransformers(ClassLoader classLoader) throws MojoExecutionException { List transformerInstances = new ArrayList<>(); diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index 04849cdb1..78206cc91 100644 --- a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java +++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -39,13 +39,13 @@ import org.apache.maven.project.MavenProject; import org.teavm.common.FiniteExecutor; import org.teavm.common.SimpleFiniteExecutor; import org.teavm.common.ThreadPoolFiniteExecutor; -import org.teavm.javascript.DirectoryBuildTarget; -import org.teavm.javascript.JavascriptBuilder; -import org.teavm.javascript.JavascriptBuilderFactory; import org.teavm.model.*; import org.teavm.parsing.ClasspathClassHolderSource; import org.teavm.testing.JUnitTestAdapter; import org.teavm.testing.TestAdapter; +import org.teavm.vm.DirectoryBuildTarget; +import org.teavm.vm.TeaVM; +import org.teavm.vm.TeaVMBuilder; /** * @@ -311,33 +311,33 @@ public class BuildJavascriptTestMojo extends AbstractMojo { private void decompileClassesForTest(ClassLoader classLoader, ClassHolderSource classSource, MethodReference methodRef, String targetName, FiniteExecutor executor) throws IOException { - JavascriptBuilderFactory builderFactory = new JavascriptBuilderFactory(); - builderFactory.setClassLoader(classLoader); - builderFactory.setClassSource(classSource); - builderFactory.setExecutor(executor); - JavascriptBuilder builder = builderFactory.create(); - builder.setMinifying(minifying); - builder.installPlugins(); + TeaVM vm = new TeaVMBuilder() + .setClassLoader(classLoader) + .setClassSource(classSource) + .setExecutor(executor) + .build(); + vm.setMinifying(minifying); + vm.installPlugins(); for (ClassHolderTransformer transformer : transformerInstances) { - builder.add(transformer); + vm.add(transformer); } - builder.prepare(); + vm.prepare(); File file = new File(outputDir, targetName); try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) { MethodReference cons = new MethodReference(methodRef.getClassName(), new MethodDescriptor("", ValueType.VOID)); - builder.entryPoint("initInstance", cons); - builder.entryPoint("runTest", methodRef).withValue(0, cons.getClassName()); - builder.exportType("TestClass", cons.getClassName()); - builder.build(innerWriter, new DirectoryBuildTarget(outputDir)); - if (!builder.hasMissingItems()) { + vm.entryPoint("initInstance", cons); + vm.entryPoint("runTest", methodRef).withValue(0, cons.getClassName()); + vm.exportType("TestClass", cons.getClassName()); + vm.build(innerWriter, new DirectoryBuildTarget(outputDir)); + if (!vm.hasMissingItems()) { innerWriter.append("\n"); innerWriter.append("\nJUnitClient.run();"); innerWriter.close(); } else { innerWriter.append("JUnitClient.reportError(\n"); StringBuilder sb = new StringBuilder(); - builder.showMissingItems(sb); + vm.showMissingItems(sb); escapeStringLiteral(sb.toString(), innerWriter); innerWriter.append(");"); getLog().warn("Error building test " + methodRef);