diff --git a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index cceaf4452..f1dbd2ec3 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -24,15 +24,12 @@ import java.util.ServiceLoader; import org.teavm.classlib.impl.lambda.LambdaMetafactorySubstitutor; import org.teavm.classlib.impl.unicode.CLDRReader; import org.teavm.classlib.java.lang.reflect.AnnotationDependencyListener; +import org.teavm.javascript.target.TeaVMJavaScriptHost; import org.teavm.model.MethodReference; import org.teavm.platform.PlatformClass; import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMPlugin; -/** - * - * @author Alexey Andreev - */ public class JCLPlugin implements TeaVMPlugin { @Override public void install(TeaVMHost host) { @@ -40,7 +37,11 @@ public class JCLPlugin implements TeaVMPlugin { host.add(serviceLoaderSupp); MethodReference loadServicesMethod = new MethodReference(ServiceLoader.class, "loadServices", PlatformClass.class, Object[].class); - host.add(loadServicesMethod, serviceLoaderSupp); + TeaVMJavaScriptHost jsExtension = host.getExtension(TeaVMJavaScriptHost.class); + if (jsExtension != null) { + jsExtension.add(loadServicesMethod, serviceLoaderSupp); + } + JavacSupport javacSupport = new JavacSupport(); host.add(javacSupport); diff --git a/classlib/teavm-classlib.iml b/classlib/teavm-classlib.iml index c1979e489..ecab2af5b 100644 --- a/classlib/teavm-classlib.iml +++ b/classlib/teavm-classlib.iml @@ -14,7 +14,7 @@ - + diff --git a/core/src/main/java/org/teavm/debugging/information/DebugInformationEmitter.java b/core/src/main/java/org/teavm/debugging/information/DebugInformationEmitter.java index 02698e039..132fcea1c 100644 --- a/core/src/main/java/org/teavm/debugging/information/DebugInformationEmitter.java +++ b/core/src/main/java/org/teavm/debugging/information/DebugInformationEmitter.java @@ -18,10 +18,6 @@ package org.teavm.debugging.information; import org.teavm.codegen.LocationProvider; import org.teavm.model.MethodDescriptor; -/** - * - * @author Alexey Andreev - */ public interface DebugInformationEmitter { void setLocationProvider(LocationProvider locationProvider); diff --git a/core/src/main/java/org/teavm/vm/BuildTarget.java b/core/src/main/java/org/teavm/vm/BuildTarget.java index 928dc3243..8a067e213 100644 --- a/core/src/main/java/org/teavm/vm/BuildTarget.java +++ b/core/src/main/java/org/teavm/vm/BuildTarget.java @@ -18,10 +18,6 @@ package org.teavm.vm; import java.io.IOException; import java.io.OutputStream; -/** - * - * @author Alexey Andreev - */ public interface BuildTarget { OutputStream createResource(String fileName) throws IOException; } diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index f2b30ec62..205496dc9 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -19,58 +19,32 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; import java.io.UnsupportedEncodingException; -import java.io.Writer; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.ServiceLoader; -import java.util.Set; +import java.util.stream.Collectors; import org.teavm.cache.NoCache; -import org.teavm.codegen.AliasProvider; -import org.teavm.codegen.DefaultAliasProvider; -import org.teavm.codegen.DefaultNamingStrategy; -import org.teavm.codegen.MinifyingAliasProvider; -import org.teavm.codegen.SourceWriter; -import org.teavm.codegen.SourceWriterBuilder; import org.teavm.common.ServiceRepository; -import org.teavm.debugging.information.DebugInformationEmitter; -import org.teavm.debugging.information.SourceLocation; import org.teavm.dependency.BootstrapMethodSubstitutor; import org.teavm.dependency.DependencyChecker; import org.teavm.dependency.DependencyInfo; import org.teavm.dependency.DependencyListener; import org.teavm.dependency.Linker; -import org.teavm.dependency.MethodDependency; import org.teavm.diagnostics.AccumulationDiagnostics; +import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.ProblemProvider; -import org.teavm.javascript.Decompiler; -import org.teavm.javascript.EmptyRegularMethodNodeCache; -import org.teavm.javascript.MethodNodeCache; -import org.teavm.javascript.Renderer; import org.teavm.javascript.RenderingException; -import org.teavm.javascript.ast.ClassNode; -import org.teavm.javascript.spi.GeneratedBy; -import org.teavm.javascript.spi.Generator; -import org.teavm.javascript.spi.InjectedBy; -import org.teavm.javascript.spi.Injector; -import org.teavm.model.BasicBlock; -import org.teavm.model.CallLocation; import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolderSource; import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassReader; import org.teavm.model.ClassReaderSource; -import org.teavm.model.ElementHolder; -import org.teavm.model.ElementModifier; -import org.teavm.model.InstructionLocation; import org.teavm.model.ListableClassHolderSource; import org.teavm.model.ListableClassReaderSource; import org.teavm.model.MethodHolder; @@ -78,15 +52,6 @@ import org.teavm.model.MethodReference; import org.teavm.model.MutableClassHolderSource; import org.teavm.model.Program; import org.teavm.model.ProgramCache; -import org.teavm.model.ValueType; -import org.teavm.model.Variable; -import org.teavm.model.instructions.ConstructInstruction; -import org.teavm.model.instructions.InvocationType; -import org.teavm.model.instructions.InvokeInstruction; -import org.teavm.model.instructions.RaiseInstruction; -import org.teavm.model.instructions.StringConstantInstruction; -import org.teavm.model.util.AsyncMethodFinder; -import org.teavm.model.util.ListingBuilder; import org.teavm.model.util.MissingItemsProcessor; import org.teavm.model.util.ModelUtils; import org.teavm.model.util.ProgramUtils; @@ -103,8 +68,8 @@ import org.teavm.optimization.MethodOptimization; import org.teavm.optimization.RedundantJumpElimination; import org.teavm.optimization.UnreachableBasicBlockElimination; import org.teavm.optimization.UnusedVariableElimination; -import org.teavm.vm.spi.RendererListener; import org.teavm.vm.spi.TeaVMHost; +import org.teavm.vm.spi.TeaVMHostExtension; import org.teavm.vm.spi.TeaVMPlugin; /** @@ -141,29 +106,24 @@ public class TeaVM implements TeaVMHost, ServiceRepository { private final DependencyChecker dependencyChecker; private final AccumulationDiagnostics diagnostics = new AccumulationDiagnostics(); private final ClassLoader classLoader; - private boolean minifying = true; - private boolean bytecodeLogging; - private final OutputStream logStream = System.out; private final Map entryPoints = new HashMap<>(); + private final Map readonlyEntryPoints = Collections.unmodifiableMap(entryPoints); private final Map exportedClasses = new HashMap<>(); - private final Map methodGenerators = new HashMap<>(); - private final Map methodInjectors = new HashMap<>(); - private final List rendererListeners = new ArrayList<>(); + private final Map readonlyExportedClasses = Collections.unmodifiableMap(exportedClasses); private final Map, Object> services = new HashMap<>(); private final Properties properties = new Properties(); - private DebugInformationEmitter debugEmitter; private ProgramCache programCache; - private MethodNodeCache astCache = new EmptyRegularMethodNodeCache(); private boolean incremental; private TeaVMProgressListener progressListener; private boolean cancelled; private ListableClassHolderSource writtenClasses; - private final Set asyncMethods = new HashSet<>(); - private final Set asyncFamilyMethods = new HashSet<>(); + private TeaVMTarget target; + private Map, TeaVMHostExtension> extensions = new HashMap<>(); - TeaVM(ClassReaderSource classSource, ClassLoader classLoader) { - this.classSource = classSource; - this.classLoader = classLoader; + TeaVM(TeaVMBuilder builder) { + target = builder.target; + classSource = builder.classSource; + classLoader = builder.classLoader; dependencyChecker = new DependencyChecker(this.classSource, classLoader, this, diagnostics); progressListener = new TeaVMProgressListener() { @Override public TeaVMProgressFeedback progressReached(int progress) { @@ -173,6 +133,12 @@ public class TeaVM implements TeaVMHost, ServiceRepository { return TeaVMProgressFeedback.CONTINUE; } }; + + for (TeaVMHostExtension extension : target.getHostExtensions()) { + for (Class extensionType : getExtensionTypes(extension)) { + extensions.put(extensionType, extension); + } + } } @Override @@ -185,59 +151,16 @@ public class TeaVM implements TeaVMHost, ServiceRepository { dependencyChecker.addClassTransformer(transformer); } - @Override - public void add(MethodReference methodRef, Generator generator) { - methodGenerators.put(methodRef, generator); - } - - @Override - public void add(MethodReference methodRef, Injector injector) { - methodInjectors.put(methodRef, injector); - } - @Override public void add(MethodReference methodRef, BootstrapMethodSubstitutor substitutor) { dependencyChecker.addBootstrapMethodSubstitutor(methodRef, substitutor); } - @Override - public void add(RendererListener listener) { - rendererListeners.add(listener); - } - @Override public ClassLoader getClassLoader() { return classLoader; } - /** - * Reports whether this TeaVM instance uses obfuscation when generating the JavaScript code. - * - * @see #setMinifying(boolean) - * @return whether TeaVM produces obfuscated code. - */ - public boolean isMinifying() { - return minifying; - } - - /** - * Specifies whether this TeaVM instance uses obfuscation when generating the JavaScript code. - * - * @see #isMinifying() - * @param minifying whether TeaVM should obfuscate code. - */ - public void setMinifying(boolean minifying) { - this.minifying = minifying; - } - - public boolean isBytecodeLogging() { - return bytecodeLogging; - } - - public void setBytecodeLogging(boolean bytecodeLogging) { - this.bytecodeLogging = bytecodeLogging; - } - /** * Specifies configuration properties for TeaVM and its plugins. You should call this method before * installing any plugins or interceptors. @@ -257,14 +180,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository { return new Properties(properties); } - public MethodNodeCache getAstCache() { - return astCache; - } - - public void setAstCache(MethodNodeCache methodAstCache) { - this.astCache = methodAstCache; - } - public ProgramCache getProgramCache() { return programCache; } @@ -391,14 +306,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository { return writtenClasses; } - public DebugInformationEmitter getDebugEmitter() { - return debugEmitter; - } - - public void setDebugEmitter(DebugInformationEmitter debugEmitter) { - this.debugEmitter = debugEmitter; - } - /** *

Does actual build. Call this method after TeaVM is fully configured and all entry points * are specified. This method may fail if there are items (classes, methods and fields) @@ -406,52 +313,23 @@ public class TeaVM implements TeaVMHost, ServiceRepository { * actual generation happens and no exceptions thrown, but you can further call * {@link #getProblemProvider()} to learn the build state.

* - * @param writer where to generate JavaScript. Should not be null. - * @param target where to generate additional resources. Can be null, but if there are + * @param output where to generate JavaScript. Should not be null. + * @param buildTarget where to generate additional resources. Can be null, but if there are * plugins or inteceptors that generate additional resources, the build process will fail. * * @throws RenderingException when something went wrong during rendering phase. */ - public void build(Appendable writer, BuildTarget target) throws RenderingException { + public void build(OutputStream output, BuildTarget buildTarget) throws RenderingException { + target.setController(targetController); + // Check dependencies reportPhase(TeaVMPhase.DEPENDENCY_CHECKING, 1); if (wasCancelled()) { return; } - AliasProvider aliasProvider = minifying ? new MinifyingAliasProvider() : new DefaultAliasProvider(); dependencyChecker.setInterruptor(() -> progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE); - dependencyChecker.linkMethod(new MethodReference(Class.class.getName(), "getClass", - ValueType.object("org.teavm.platform.PlatformClass"), ValueType.parse(Class.class)), null).use(); - dependencyChecker.linkMethod(new MethodReference(String.class, "", char[].class, void.class), - null).use(); - dependencyChecker.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, char[].class, - int.class, void.class), null).use(); - MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference(String.class, "intern", - String.class), null); - internDep.getVariable(0).propagate(dependencyChecker.getType("java.lang.String")); - internDep.use(); - dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class), null).use(); - dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use(); - dependencyChecker.linkMethod(new MethodReference(Thread.class, "currentThread", Thread.class), null).use(); - dependencyChecker.linkMethod(new MethodReference(Thread.class, "getMainThread", Thread.class), null).use(); - dependencyChecker.linkMethod( - new MethodReference(Thread.class, "setCurrentThread", Thread.class, void.class), null).use(); - MethodDependency exceptionCons = dependencyChecker.linkMethod(new MethodReference( - NoClassDefFoundError.class, "", String.class, void.class), null); - exceptionCons.use(); - exceptionCons.getVariable(0).propagate(dependencyChecker.getType(NoClassDefFoundError.class.getName())); - exceptionCons.getVariable(1).propagate(dependencyChecker.getType("java.lang.String")); - exceptionCons = dependencyChecker.linkMethod(new MethodReference(NoSuchFieldError.class, "", - String.class, void.class), null); - exceptionCons.use(); - exceptionCons.getVariable(0).propagate(dependencyChecker.getType(NoSuchFieldError.class.getName())); - exceptionCons.getVariable(1).propagate(dependencyChecker.getType("java.lang.String")); - exceptionCons = dependencyChecker.linkMethod(new MethodReference(NoSuchMethodError.class, "", - String.class, void.class), null); - exceptionCons.use(); - exceptionCons.getVariable(0).propagate(dependencyChecker.getType(NoSuchMethodError.class.getName())); - exceptionCons.getVariable(1).propagate(dependencyChecker.getType("java.lang.String")); + target.contributeDependencies(dependencyChecker); dependencyChecker.processDependencies(); if (wasCancelled() || !diagnostics.getSevereProblems().isEmpty()) { return; @@ -469,73 +347,27 @@ public class TeaVM implements TeaVMHost, ServiceRepository { } // Optimize and allocate registers + reportPhase(TeaVMPhase.OPTIMIZATION, 1); + if (!incremental) { devirtualize(classSet, dependencyChecker); if (wasCancelled()) { return; } + + inline(classSet); + if (wasCancelled()) { + return; + } } - List clsNodes = modelToAst(classSet); - - // Render - reportPhase(TeaVMPhase.RENDERING, classSet.getClassNames().size()); + optimize(classSet); if (wasCancelled()) { return; } - DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, dependencyChecker.getClassSource()); - SourceWriterBuilder builder = new SourceWriterBuilder(naming); - builder.setMinified(minifying); - SourceWriter sourceWriter = builder.build(writer); - Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this, asyncMethods, asyncFamilyMethods, - diagnostics); - renderer.setProperties(properties); - renderer.setMinifying(minifying); - if (debugEmitter != null) { - int classIndex = 0; - for (String className : classSet.getClassNames()) { - ClassHolder cls = classSet.get(className); - for (MethodHolder method : cls.getMethods()) { - if (method.getProgram() != null) { - emitCFG(debugEmitter, method.getProgram()); - } - } - reportProgress(++classIndex); - if (wasCancelled()) { - return; - } - } - renderer.setDebugEmitter(debugEmitter); - } - renderer.getDebugEmitter().setLocationProvider(sourceWriter); - for (Map.Entry entry : methodInjectors.entrySet()) { - renderer.addInjector(entry.getKey(), entry.getValue()); - } - try { - for (RendererListener listener : rendererListeners) { - listener.begin(renderer, target); - } - sourceWriter.append("\"use strict\";").newLine(); - renderer.renderRuntime(); - renderer.render(clsNodes); - renderer.renderStringPool(); - renderer.renderStringConstants(); - for (Map.Entry entry : entryPoints.entrySet()) { - sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws(); - MethodReference ref = entry.getValue().reference; - sourceWriter.append(naming.getFullNameFor(ref)); - sourceWriter.append(";").newLine(); - } - for (Map.Entry entry : exportedClasses.entrySet()) { - sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws() - .appendClass(entry.getValue()).append(";").newLine(); - } - for (RendererListener listener : rendererListeners) { - listener.complete(); - } - } catch (IOException e) { - throw new RenderingException("IO Error occured", e); - } + + // Render + target.emit(classSet, output, buildTarget); } @SuppressWarnings("WeakerAccess") @@ -568,38 +400,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository { } } - private void reportProgress(int progress) { - if (progressListener.progressReached(progress) == TeaVMProgressFeedback.CANCEL) { - cancelled = true; - } - } - - private void emitCFG(DebugInformationEmitter emitter, Program program) { - Map cfg = ProgramUtils.getLocationCFG(program); - for (Map.Entry entry : cfg.entrySet()) { - SourceLocation location = map(entry.getKey()); - SourceLocation[] successors = new SourceLocation[entry.getValue().length]; - for (int i = 0; i < entry.getValue().length; ++i) { - successors[i] = map(entry.getValue()[i]); - } - emitter.addSuccessors(location, successors); - } - } - - private static SourceLocation map(InstructionLocation location) { - if (location == null) { - return null; - } - return new SourceLocation(location.getFileName(), location.getLine()); - } - - private void devirtualize(ListableClassHolderSource classes, DependencyInfo dependency) { - reportPhase(TeaVMPhase.DEVIRTUALIZATION, classes.getClassNames().size()); + private void devirtualize(ListableClassHolderSource classes, DependencyInfo dependency) { if (wasCancelled()) { return; } Devirtualization devirtualization = new Devirtualization(dependency, classes); - int index = 0; for (String className : classes.getClassNames()) { ClassHolder cls = classes.get(className); for (final MethodHolder method : cls.getMethods()) { @@ -607,12 +412,13 @@ public class TeaVM implements TeaVMHost, ServiceRepository { devirtualization.apply(method); } } - reportProgress(++index); if (wasCancelled()) { return; } } + } + private void inline(ListableClassHolderSource classes) { Inlining inlining = new Inlining(); for (String className : classes.getClassNames()) { ClassHolder cls = classes.get(className); @@ -621,90 +427,22 @@ public class TeaVM implements TeaVMHost, ServiceRepository { inlining.apply(method.getProgram(), classes); } } - reportProgress(++index); if (wasCancelled()) { return; } } } - private List modelToAst(ListableClassHolderSource classes) { - AsyncMethodFinder asyncFinder = new AsyncMethodFinder(dependencyChecker.getCallGraph(), diagnostics); - asyncFinder.find(classes); - asyncMethods.addAll(asyncFinder.getAsyncMethods()); - asyncFamilyMethods.addAll(asyncFinder.getAsyncFamilyMethods()); - - progressListener.phaseStarted(TeaVMPhase.DECOMPILATION, classes.getClassNames().size()); - Decompiler decompiler = new Decompiler(classes, classLoader, asyncMethods, asyncFamilyMethods); - decompiler.setRegularMethodCache(incremental ? astCache : null); - - for (Map.Entry entry : methodGenerators.entrySet()) { - decompiler.addGenerator(entry.getKey(), entry.getValue()); - } - for (MethodReference injectedMethod : methodInjectors.keySet()) { - decompiler.addMethodToPass(injectedMethod); - } - List classOrder = decompiler.getClassOrdering(classes.getClassNames()); - List classNodes = new ArrayList<>(); - int index = 0; - try (PrintWriter bytecodeLogger = bytecodeLogging - ? new PrintWriter(new OutputStreamWriter(logStream, "UTF-8")) : null) { - for (String className : classOrder) { - ClassHolder cls = classes.get(className); - for (MethodHolder method : cls.getMethods()) { - processMethod(method); - preprocessNativeMethod(method); - if (bytecodeLogging) { - logMethodBytecode(bytecodeLogger, method); - } - } - classNodes.add(decompiler.decompile(cls)); - progressListener.progressReached(++index); + private void optimize(ListableClassHolderSource classSource) { + for (String className : classSource.getClassNames()) { + ClassHolder cls = classSource.get(className); + for (MethodHolder method : cls.getMethods()) { + processMethod(method); + } + if (wasCancelled()) { + return; } - } catch (UnsupportedEncodingException e) { - throw new AssertionError("UTF-8 is expected to be supported"); } - return classNodes; - } - - private void preprocessNativeMethod(MethodHolder method) { - if (!method.getModifiers().contains(ElementModifier.NATIVE) - || methodGenerators.get(method.getReference()) != null - || methodInjectors.get(method.getReference()) != null - || method.getAnnotations().get(GeneratedBy.class.getName()) != null - || method.getAnnotations().get(InjectedBy.class.getName()) != null) { - return; - } - method.getModifiers().remove(ElementModifier.NATIVE); - - Program program = new Program(); - method.setProgram(program); - BasicBlock block = program.createBasicBlock(); - Variable exceptionVar = program.createVariable(); - ConstructInstruction newExceptionInsn = new ConstructInstruction(); - newExceptionInsn.setType(NoSuchMethodError.class.getName()); - newExceptionInsn.setReceiver(exceptionVar); - block.getInstructions().add(newExceptionInsn); - - Variable constVar = program.createVariable(); - StringConstantInstruction constInsn = new StringConstantInstruction(); - constInsn.setConstant("Native method implementation not found: " + method.getReference()); - constInsn.setReceiver(constVar); - block.getInstructions().add(constInsn); - - InvokeInstruction initExceptionInsn = new InvokeInstruction(); - initExceptionInsn.setInstance(exceptionVar); - initExceptionInsn.setMethod(new MethodReference(NoSuchMethodError.class, "", String.class, void.class)); - initExceptionInsn.setType(InvocationType.SPECIAL); - initExceptionInsn.getArguments().add(constVar); - block.getInstructions().add(initExceptionInsn); - - RaiseInstruction raiseInsn = new RaiseInstruction(); - raiseInsn.setException(exceptionVar); - block.getInstructions().add(raiseInsn); - - diagnostics.error(new CallLocation(method.getReference()), "Native method {{m0}} has no implementation", - method.getReference()); } private void processMethod(MethodHolder method) { @@ -725,8 +463,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository { changed |= optimization.optimize(method, optimizedProgram); } } while (changed); - RegisterAllocator allocator = new RegisterAllocator(); - allocator.allocateRegisters(method, optimizedProgram); + + if (target.requiresRegisterAllocation()) { + RegisterAllocator allocator = new RegisterAllocator(); + allocator.allocateRegisters(method, optimizedProgram); + } } if (incremental && programCache != null) { programCache.store(method.getReference(), optimizedProgram); @@ -749,102 +490,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository { new UnreachableBasicBlockElimination()); } - private void logMethodBytecode(PrintWriter writer, MethodHolder method) { - writer.print(" "); - printModifiers(writer, method); - writer.print(method.getName() + "("); - ValueType[] parameterTypes = method.getParameterTypes(); - for (int i = 0; i < parameterTypes.length; ++i) { - if (i > 0) { - writer.print(", "); - } - printType(writer, parameterTypes[i]); - } - writer.println(")"); - Program program = method.getProgram(); - if (program != null && program.basicBlockCount() > 0) { - ListingBuilder builder = new ListingBuilder(); - writer.print(builder.buildListing(program, " ")); - writer.print(" Register allocation:"); - for (int i = 0; i < program.variableCount(); ++i) { - writer.print(i + ":" + program.variableAt(i).getRegister() + " "); - } - writer.println(); - writer.println(); - writer.flush(); - } else { - writer.println(); - } - } - - private void printType(PrintWriter writer, ValueType type) { - if (type instanceof ValueType.Object) { - writer.print(((ValueType.Object) type).getClassName()); - } else if (type instanceof ValueType.Array) { - printType(writer, ((ValueType.Array) type).getItemType()); - writer.print("[]"); - } else if (type instanceof ValueType.Primitive) { - switch (((ValueType.Primitive) type).getKind()) { - case BOOLEAN: - writer.print("boolean"); - break; - case SHORT: - writer.print("short"); - break; - case BYTE: - writer.print("byte"); - break; - case CHARACTER: - writer.print("char"); - break; - case DOUBLE: - writer.print("double"); - break; - case FLOAT: - writer.print("float"); - break; - case INTEGER: - writer.print("int"); - break; - case LONG: - writer.print("long"); - break; - } - } - } - - private void printModifiers(PrintWriter writer, ElementHolder element) { - switch (element.getLevel()) { - case PRIVATE: - writer.print("private "); - break; - case PUBLIC: - writer.print("public "); - break; - case PROTECTED: - writer.print("protected "); - break; - default: - break; - } - Set modifiers = element.getModifiers(); - if (modifiers.contains(ElementModifier.ABSTRACT)) { - writer.print("abstract "); - } - if (modifiers.contains(ElementModifier.FINAL)) { - writer.print("final "); - } - if (modifiers.contains(ElementModifier.STATIC)) { - writer.print("static "); - } - if (modifiers.contains(ElementModifier.NATIVE)) { - writer.print("native "); - } - } - public void build(File dir, String fileName) throws RenderingException { - try (Writer writer = new OutputStreamWriter(new FileOutputStream(new File(dir, fileName)), "UTF-8")) { - build(writer, new DirectoryBuildTarget(dir)); + try (OutputStream output = new FileOutputStream(new File(dir, fileName))) { + build(output, new DirectoryBuildTarget(dir)); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Platform does not support UTF-8", e); } catch (IOException e) { @@ -877,4 +525,69 @@ public class TeaVM implements TeaVMHost, ServiceRepository { public void registerService(Class type, T instance) { services.put(type, instance); } + + @Override + public T getExtension(Class extensionType) { + Object extension = extensions.get(extensionType); + return extension != null ? extensionType.cast(extension) : null; + } + + private Collection> getExtensionTypes(TeaVMHostExtension extension) { + return Arrays.stream(extension.getClass().getInterfaces()) + .filter(cls -> cls.isInterface() && TeaVMHostExtension.class.isAssignableFrom(cls)) + .>map(cls -> cls.asSubclass(TeaVMHostExtension.class)) + .collect(Collectors.toSet()); + } + + private TeaVMTargetController targetController = new TeaVMTargetController() { + @Override + public boolean wasCancelled() { + return TeaVM.this.wasCancelled(); + } + + @Override + public ClassLoader getClassLoader() { + return classLoader; + } + + @Override + public ClassReaderSource getUnprocessedClassSource() { + return dependencyChecker.getClassSource(); + } + + @Override + public DependencyInfo getDependencyInfo() { + return dependencyChecker; + } + + @Override + public Diagnostics getDiagnostics() { + return diagnostics; + } + + @Override + public Properties getProperties() { + return properties; + } + + @Override + public ServiceRepository getServices() { + return TeaVM.this; + } + + @Override + public boolean isIncremental() { + return incremental; + } + + @Override + public Map getEntryPoints() { + return readonlyEntryPoints; + } + + @Override + public Map getExportedClasses() { + return readonlyExportedClasses; + } + }; } diff --git a/core/src/main/java/org/teavm/vm/TeaVMBuilder.java b/core/src/main/java/org/teavm/vm/TeaVMBuilder.java index ad926fcbf..fbc7599c4 100644 --- a/core/src/main/java/org/teavm/vm/TeaVMBuilder.java +++ b/core/src/main/java/org/teavm/vm/TeaVMBuilder.java @@ -18,15 +18,13 @@ package org.teavm.vm; import org.teavm.model.ClassHolderSource; import org.teavm.parsing.ClasspathClassHolderSource; -/** - * - * @author Alexey Andreev - */ public class TeaVMBuilder { + TeaVMTarget target; ClassHolderSource classSource; ClassLoader classLoader; - public TeaVMBuilder() { + public TeaVMBuilder(TeaVMTarget target) { + this.target = target; classLoader = TeaVMBuilder.class.getClassLoader(); classSource = new ClasspathClassHolderSource(classLoader); } @@ -50,6 +48,6 @@ public class TeaVMBuilder { } public TeaVM build() { - return new TeaVM(classSource, classLoader); + return new TeaVM(this); } } diff --git a/core/src/main/java/org/teavm/vm/TeaVMEntryPoint.java b/core/src/main/java/org/teavm/vm/TeaVMEntryPoint.java index 0c8f40bbc..dec5d52db 100644 --- a/core/src/main/java/org/teavm/vm/TeaVMEntryPoint.java +++ b/core/src/main/java/org/teavm/vm/TeaVMEntryPoint.java @@ -81,6 +81,10 @@ public class TeaVMEntryPoint { method.use(); } + public MethodReference getReference() { + return reference; + } + String getPublicName() { return publicName; } diff --git a/core/src/main/java/org/teavm/vm/TeaVMPhase.java b/core/src/main/java/org/teavm/vm/TeaVMPhase.java index a74621432..482b6243c 100644 --- a/core/src/main/java/org/teavm/vm/TeaVMPhase.java +++ b/core/src/main/java/org/teavm/vm/TeaVMPhase.java @@ -15,14 +15,10 @@ */ package org.teavm.vm; -/** - * - * @author Alexey Andreev - */ public enum TeaVMPhase { DEPENDENCY_CHECKING, LINKING, - DEVIRTUALIZATION, + OPTIMIZATION, DECOMPILATION, RENDERING } diff --git a/core/src/main/java/org/teavm/vm/TeaVMTarget.java b/core/src/main/java/org/teavm/vm/TeaVMTarget.java new file mode 100644 index 000000000..496757937 --- /dev/null +++ b/core/src/main/java/org/teavm/vm/TeaVMTarget.java @@ -0,0 +1,34 @@ +/* + * Copyright 2016 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; + +import java.io.OutputStream; +import java.util.List; +import org.teavm.dependency.DependencyChecker; +import org.teavm.model.ListableClassHolderSource; +import org.teavm.vm.spi.TeaVMHostExtension; + +public interface TeaVMTarget { + void setController(TeaVMTargetController controller); + + List getHostExtensions(); + + boolean requiresRegisterAllocation(); + + void contributeDependencies(DependencyChecker dependencyChecker); + + void emit(ListableClassHolderSource classes, OutputStream output, BuildTarget buildTarget); +} diff --git a/core/src/main/java/org/teavm/vm/TeaVMTargetController.java b/core/src/main/java/org/teavm/vm/TeaVMTargetController.java new file mode 100644 index 000000000..28ff0125c --- /dev/null +++ b/core/src/main/java/org/teavm/vm/TeaVMTargetController.java @@ -0,0 +1,45 @@ +/* + * Copyright 2016 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; + +import java.util.Map; +import java.util.Properties; +import org.teavm.common.ServiceRepository; +import org.teavm.dependency.DependencyInfo; +import org.teavm.diagnostics.Diagnostics; +import org.teavm.model.ClassReaderSource; + +public interface TeaVMTargetController { + boolean wasCancelled(); + + ClassLoader getClassLoader(); + + ClassReaderSource getUnprocessedClassSource(); + + DependencyInfo getDependencyInfo(); + + Diagnostics getDiagnostics(); + + Properties getProperties(); + + ServiceRepository getServices(); + + boolean isIncremental(); + + Map getEntryPoints(); + + Map getExportedClasses(); +} diff --git a/core/src/main/java/org/teavm/vm/spi/TeaVMHost.java b/core/src/main/java/org/teavm/vm/spi/TeaVMHost.java index e4877202e..b247b296f 100644 --- a/core/src/main/java/org/teavm/vm/spi/TeaVMHost.java +++ b/core/src/main/java/org/teavm/vm/spi/TeaVMHost.java @@ -18,8 +18,6 @@ package org.teavm.vm.spi; import java.util.Properties; import org.teavm.dependency.BootstrapMethodSubstitutor; import org.teavm.dependency.DependencyListener; -import org.teavm.javascript.spi.Generator; -import org.teavm.javascript.spi.Injector; import org.teavm.model.ClassHolderTransformer; import org.teavm.model.MethodReference; import org.teavm.vm.TeaVM; @@ -36,13 +34,9 @@ public interface TeaVMHost { void add(ClassHolderTransformer classTransformer); - void add(MethodReference methodRef, Generator generator); - - void add(MethodReference methodRef, Injector injector); - void add(MethodReference methodRef, BootstrapMethodSubstitutor substitutor); - void add(RendererListener listener); + T getExtension(Class extensionType); void registerService(Class type, T instance); diff --git a/core/src/main/java/org/teavm/vm/spi/TeaVMHostExtension.java b/core/src/main/java/org/teavm/vm/spi/TeaVMHostExtension.java new file mode 100644 index 000000000..9bc35477d --- /dev/null +++ b/core/src/main/java/org/teavm/vm/spi/TeaVMHostExtension.java @@ -0,0 +1,19 @@ +/* + * Copyright 2016 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; + +public interface TeaVMHostExtension { +} diff --git a/core/src/main/java/org/teavm/vm/spi/TeaVMPlugin.java b/core/src/main/java/org/teavm/vm/spi/TeaVMPlugin.java index 63c1e61ba..eca296c71 100644 --- a/core/src/main/java/org/teavm/vm/spi/TeaVMPlugin.java +++ b/core/src/main/java/org/teavm/vm/spi/TeaVMPlugin.java @@ -15,10 +15,6 @@ */ package org.teavm.vm.spi; -/** - * - * @author Alexey Andreev - */ public interface TeaVMPlugin { void install(TeaVMHost host); } diff --git a/html4j/src/main/java/org/teavm/html4j/HTML4JPlugin.java b/html4j/src/main/java/org/teavm/html4j/HTML4JPlugin.java index 1530d308d..9c935dc2f 100644 --- a/html4j/src/main/java/org/teavm/html4j/HTML4JPlugin.java +++ b/html4j/src/main/java/org/teavm/html4j/HTML4JPlugin.java @@ -15,19 +15,20 @@ */ package org.teavm.html4j; +import org.teavm.javascript.target.TeaVMJavaScriptHost; import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMPlugin; -/** - * - * @author Alexey Andreev - */ public class HTML4JPlugin implements TeaVMPlugin { @Override public void install(TeaVMHost host) { + if (host.getExtension(TeaVMJavaScriptHost.class) == null) { + return; + } host.add(new JavaScriptBodyDependency()); host.add(new JavaScriptBodyTransformer()); host.add(new JCLHacks()); - host.add(new JavaScriptResourceInterceptor()); + + host.getExtension(TeaVMJavaScriptHost.class).add(new JavaScriptResourceInterceptor()); } } diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSOPlugin.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSOPlugin.java index 4535f4349..d16904468 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSOPlugin.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSOPlugin.java @@ -15,22 +15,23 @@ */ package org.teavm.jso.impl; +import org.teavm.javascript.target.TeaVMJavaScriptHost; import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMPlugin; -/** - * - * @author Alexey Andreev - */ public class JSOPlugin implements TeaVMPlugin { @Override public void install(TeaVMHost host) { + if (host.getExtension(TeaVMJavaScriptHost.class) == null) { + return; + } + JSBodyRepository repository = new JSBodyRepository(); host.registerService(JSBodyRepository.class, repository); host.add(new JSObjectClassTransformer(repository)); JSDependencyListener dependencyListener = new JSDependencyListener(repository); JSAliasRenderer aliasRenderer = new JSAliasRenderer(dependencyListener); host.add(dependencyListener); - host.add(aliasRenderer); + host.getExtension(TeaVMJavaScriptHost.class).add(aliasRenderer); } } diff --git a/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java b/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java index 0c7c3e080..34b51f4fb 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java +++ b/platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java @@ -18,10 +18,6 @@ package org.teavm.platform.plugin; import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMPlugin; -/** - * - * @author Alexey Andreev - */ public class PlatformPlugin implements TeaVMPlugin { @Override public void install(TeaVMHost host) { diff --git a/platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java b/platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java index 9e4afdd3a..bbf83dbbe 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java +++ b/platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java @@ -16,18 +16,15 @@ package org.teavm.platform.plugin; import org.teavm.diagnostics.Diagnostics; +import org.teavm.javascript.target.TeaVMJavaScriptHost; import org.teavm.model.*; import org.teavm.vm.spi.TeaVMHost; -/** - * - * @author Alexey Andreev - */ class ResourceAccessorTransformer implements ClassHolderTransformer { - private TeaVMHost vm; + private TeaVMJavaScriptHost vm; public ResourceAccessorTransformer(TeaVMHost vm) { - this.vm = vm; + this.vm = vm.getExtension(TeaVMJavaScriptHost.class); } @Override diff --git a/tests/src/test/java/org/teavm/dependency/ClassValueTest.java b/tests/src/test/java/org/teavm/dependency/ClassValueTest.java index 2dbb914ae..c78af0db5 100644 --- a/tests/src/test/java/org/teavm/dependency/ClassValueTest.java +++ b/tests/src/test/java/org/teavm/dependency/ClassValueTest.java @@ -17,7 +17,9 @@ package org.teavm.dependency; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.apache.commons.io.output.ByteArrayOutputStream; import org.junit.Test; +import org.teavm.javascript.target.JavaScriptTarget; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; import org.teavm.tooling.TeaVMProblemRenderer; @@ -73,10 +75,10 @@ public class ClassValueTest { } private DependencyInfo runTest(String methodName) { - TeaVM vm = new TeaVMBuilder().build(); + TeaVM vm = new TeaVMBuilder(new JavaScriptTarget()).build(); vm.installPlugins(); vm.entryPoint(new MethodReference(getClass().getName(), methodName, ValueType.VOID)); - vm.build(new StringBuilder(), null); + vm.build(new ByteArrayOutputStream(), null); if (!vm.getProblemProvider().getSevereProblems().isEmpty()) { fail("Code compiled with errors:\n" + describeProblems(vm)); } diff --git a/tests/src/test/java/org/teavm/tests/JSOTest.java b/tests/src/test/java/org/teavm/tests/JSOTest.java index 5e9a14ef4..1a183edf3 100644 --- a/tests/src/test/java/org/teavm/tests/JSOTest.java +++ b/tests/src/test/java/org/teavm/tests/JSOTest.java @@ -15,15 +15,15 @@ */ package org.teavm.tests; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import java.io.ByteArrayOutputStream; import java.util.List; import org.junit.Test; -import org.junit.runner.RunWith; import org.teavm.diagnostics.Problem; +import org.teavm.javascript.target.JavaScriptTarget; import org.teavm.jso.JSBody; -import org.teavm.junit.SkipJVM; -import org.teavm.junit.TeaVMTestRunner; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; import org.teavm.vm.TeaVM; @@ -96,10 +96,10 @@ public class JSOTest { private static native Object jsBodyWithWrongReturningType(String value); private List build(String methodName) { - TeaVM vm = new TeaVMBuilder().build(); + TeaVM vm = new TeaVMBuilder(new JavaScriptTarget()).build(); vm.installPlugins(); vm.entryPoint("org/teavm/metaprogramming/test", new MethodReference(JSOTest.class, methodName, void.class)); - vm.build(new StringBuilder(), null); + vm.build(new ByteArrayOutputStream(), null); return vm.getProblemProvider().getSevereProblems(); } } diff --git a/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java b/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java index 9062cd5cf..1bda04d5a 100644 --- a/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java +++ b/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java @@ -27,10 +27,6 @@ import org.teavm.vm.TeaVMPhase; import org.teavm.vm.TeaVMProgressFeedback; import org.teavm.vm.TeaVMProgressListener; -/** - * - * @author Alexey Andreev - */ public final class TeaVMRunner { private static long startTime; private static long phaseStartTime; @@ -69,10 +65,6 @@ public final class TeaVMRunner { .withDescription("causes TeaVM to include default main page") .withLongOpt("mainpage") .create()); - options.addOption(OptionBuilder - .withDescription("causes TeaVM to log bytecode") - .withLongOpt("logbytecode") - .create()); options.addOption(OptionBuilder .withDescription("Generate debug information") .withLongOpt("debug") @@ -116,7 +108,6 @@ public final class TeaVMRunner { } TeaVMTool tool = new TeaVMTool(); - tool.setBytecodeLogging(commandLine.hasOption("logbytecode")); if (commandLine.hasOption("d")) { tool.setTargetDirectory(new File(commandLine.getOptionValue("d"))); } @@ -269,7 +260,7 @@ public final class TeaVMRunner { case LINKING: System.out.print("Linking methods..."); break; - case DEVIRTUALIZATION: + case OPTIMIZATION: System.out.print("Applying devirtualization..."); break; case DECOMPILATION: diff --git a/tools/core/src/main/java/org/teavm/tooling/TeaVMTargetType.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMTargetType.java new file mode 100644 index 000000000..32f774dbe --- /dev/null +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTargetType.java @@ -0,0 +1,20 @@ +/* + * Copyright 2016 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.tooling; + +public enum TeaVMTargetType { + JAVASCRIPT +} diff --git a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java index a7bf85646..e508e1ede 100644 --- a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -15,8 +15,24 @@ */ package org.teavm.tooling; -import java.io.*; -import java.util.*; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; import org.apache.commons.io.IOUtils; import org.teavm.cache.DiskCachedClassHolderSource; import org.teavm.cache.DiskProgramCache; @@ -27,26 +43,37 @@ import org.teavm.debugging.information.DebugInformationBuilder; import org.teavm.dependency.DependencyInfo; import org.teavm.diagnostics.ProblemProvider; import org.teavm.javascript.RenderingContext; -import org.teavm.model.*; +import org.teavm.javascript.target.JavaScriptTarget; +import org.teavm.model.ClassHolderSource; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.model.ClassReader; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReader; +import org.teavm.model.MethodReference; +import org.teavm.model.PreOptimizingClassHolderSource; +import org.teavm.model.ProgramReader; import org.teavm.parsing.ClasspathClassHolderSource; import org.teavm.tooling.sources.SourceFileProvider; import org.teavm.tooling.sources.SourceFilesCopier; -import org.teavm.vm.*; +import org.teavm.vm.BuildTarget; +import org.teavm.vm.DirectoryBuildTarget; +import org.teavm.vm.TeaVM; +import org.teavm.vm.TeaVMBuilder; +import org.teavm.vm.TeaVMEntryPoint; +import org.teavm.vm.TeaVMProgressListener; +import org.teavm.vm.TeaVMTarget; import org.teavm.vm.spi.AbstractRendererListener; -/** - * - * @author Alexey Andreev - */ public class TeaVMTool implements BaseTeaVMTool { private File targetDirectory = new File("."); + private TeaVMTargetType targetType = TeaVMTargetType.JAVASCRIPT; private String targetFileName = "classes.js"; private boolean minifying = true; private String mainClass; private RuntimeCopyOperation runtime = RuntimeCopyOperation.SEPARATE; private Properties properties = new Properties(); private boolean mainPageIncluded; - private boolean bytecodeLogging; private boolean debugInformationGenerated; private boolean sourceMapsFileGenerated; private boolean sourceFilesCopied; @@ -66,6 +93,8 @@ public class TeaVMTool implements BaseTeaVMTool { private TeaVMProgressListener progressListener; private TeaVM vm; private List sourceFileProviders = new ArrayList<>(); + private DebugInformationBuilder debugEmitter; + private JavaScriptTarget javaScriptTarget; public File getTargetDirectory() { return targetDirectory; @@ -126,14 +155,6 @@ public class TeaVMTool implements BaseTeaVMTool { this.mainPageIncluded = mainPageIncluded; } - public boolean isBytecodeLogging() { - return bytecodeLogging; - } - - public void setBytecodeLogging(boolean bytecodeLogging) { - this.bytecodeLogging = bytecodeLogging; - } - public boolean isDebugInformationGenerated() { return debugInformationGenerated; } @@ -262,11 +283,34 @@ public class TeaVMTool implements BaseTeaVMTool { sourceFileProviders.add(sourceFileProvider); } + private TeaVMTarget prepareTarget() { + switch (targetType) { + case JAVASCRIPT: + return prepareJavaScriptTarget(); + } + throw new IllegalStateException("Unknown target type: " + targetType); + } + + private TeaVMTarget prepareJavaScriptTarget() { + javaScriptTarget = new JavaScriptTarget(); + javaScriptTarget.setMinifying(minifying); + + DebugInformationBuilder debugEmitter = debugInformationGenerated || sourceMapsFileGenerated + ? new DebugInformationBuilder() : null; + javaScriptTarget.setDebugEmitter(debugEmitter); + + if (incremental) { + javaScriptTarget.setAstCache(astCache); + } + + return javaScriptTarget; + } + public void generate() throws TeaVMToolException { try { cancelled = false; log.info("Building JavaScript file"); - TeaVMBuilder vmBuilder = new TeaVMBuilder(); + TeaVMBuilder vmBuilder = new TeaVMBuilder(prepareTarget()); if (incremental) { cacheDirectory.mkdirs(); symbolTable = new FileSymbolTable(new File(cacheDirectory, "symbols")); @@ -276,7 +320,10 @@ public class TeaVMTool implements BaseTeaVMTool { cachedClassSource = new DiskCachedClassHolderSource(cacheDirectory, symbolTable, fileTable, classSource, innerClassSource); programCache = new DiskProgramCache(cacheDirectory, symbolTable, fileTable, innerClassSource); - astCache = new DiskRegularMethodNodeCache(cacheDirectory, symbolTable, fileTable, innerClassSource); + + if (targetType == TeaVMTargetType.JAVASCRIPT) { + astCache = new DiskRegularMethodNodeCache(cacheDirectory, symbolTable, fileTable, innerClassSource); + } try { symbolTable.update(); fileTable.update(); @@ -292,17 +339,11 @@ public class TeaVMTool implements BaseTeaVMTool { if (progressListener != null) { vm.setProgressListener(progressListener); } - vm.setMinifying(minifying); - vm.setBytecodeLogging(bytecodeLogging); + vm.setProperties(properties); - DebugInformationBuilder debugEmitter = debugInformationGenerated || sourceMapsFileGenerated - ? new DebugInformationBuilder() : null; - vm.setDebugEmitter(debugEmitter); + vm.setProgramCache(programCache); vm.setIncremental(incremental); - if (incremental) { - vm.setAstCache(astCache); - vm.setProgramCache(programCache); - } + vm.installPlugins(); for (ClassHolderTransformer transformer : transformers) { vm.add(transformer); @@ -336,82 +377,96 @@ public class TeaVMTool implements BaseTeaVMTool { } } targetDirectory.mkdirs(); - try (Writer writer = new OutputStreamWriter(new BufferedOutputStream( - new FileOutputStream(new File(targetDirectory, targetFileName)), 65536), "UTF-8")) { + try (OutputStream output = new BufferedOutputStream( + new FileOutputStream(new File(targetDirectory, targetFileName)), 65536)) { + Writer writer = new OutputStreamWriter(output, "UTF-8"); if (runtime == RuntimeCopyOperation.MERGED) { - vm.add(runtimeInjector); + javaScriptTarget.add(runtimeInjector); } - vm.build(writer, new DirectoryBuildTarget(targetDirectory)); + vm.build(output, new DirectoryBuildTarget(targetDirectory)); if (vm.wasCancelled()) { log.info("Build cancelled"); cancelled = true; return; } - if (mainClass != null) { - writer.append("main = $rt_mainStarter(main);\n"); - } + ProblemProvider problemProvider = vm.getProblemProvider(); if (problemProvider.getProblems().isEmpty()) { - log.info("JavaScript file successfully built"); + log.info("Output file successfully built"); } else if (problemProvider.getSevereProblems().isEmpty()) { - log.info("JavaScript file built with warnings"); + log.info("Output file built with warnings"); TeaVMProblemRenderer.describeProblems(vm, log); } else { - log.info("JavaScript file built with errors"); + log.info("Output file built with errors"); TeaVMProblemRenderer.describeProblems(vm, log); } - if (debugInformationGenerated) { - assert debugEmitter != null; - DebugInformation debugInfo = debugEmitter.getDebugInformation(); - try (OutputStream debugInfoOut = new FileOutputStream(new File(targetDirectory, - targetFileName + ".teavmdbg"))) { - debugInfo.write(debugInfoOut); - } - log.info("Debug information successfully written"); - } - if (sourceMapsFileGenerated) { - assert debugEmitter != null; - DebugInformation debugInfo = debugEmitter.getDebugInformation(); - String sourceMapsFileName = targetFileName + ".map"; - writer.append("\n//# sourceMappingURL=").append(sourceMapsFileName); - try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream( - new File(targetDirectory, sourceMapsFileName)), "UTF-8")) { - debugInfo.writeAsSourceMaps(sourceMapsOut, "src", targetFileName); - } - log.info("Source maps successfully written"); - } - if (sourceFilesCopied) { - copySourceFiles(); - log.info("Source files successfully written"); + + if (targetType == TeaVMTargetType.JAVASCRIPT) { + additionalJavaScriptOutput(writer); } + if (incremental) { programCache.flush(); - astCache.flush(); + if (astCache != null) { + astCache.flush(); + } cachedClassSource.flush(); symbolTable.flush(); fileTable.flush(); log.info("Cache updated"); } } - if (runtime == RuntimeCopyOperation.SEPARATE) { - resourceToFile("org/teavm/javascript/runtime.js", "runtime.js"); - } - if (mainPageIncluded) { - String text; - try (Reader reader = new InputStreamReader(classLoader.getResourceAsStream( - "org/teavm/tooling/main.html"), "UTF-8")) { - text = IOUtils.toString(reader).replace("${classes.js}", targetFileName); - } - File mainPageFile = new File(targetDirectory, "main.html"); - try (Writer writer = new OutputStreamWriter(new FileOutputStream(mainPageFile), "UTF-8")) { - writer.append(text); - } - } } catch (IOException e) { throw new TeaVMToolException("IO error occured", e); } } + private void additionalJavaScriptOutput(Writer writer) throws IOException { + if (mainClass != null) { + writer.append("main = $rt_mainStarter(main);\n"); + } + + if (debugInformationGenerated) { + assert debugEmitter != null; + DebugInformation debugInfo = debugEmitter.getDebugInformation(); + try (OutputStream debugInfoOut = new FileOutputStream(new File(targetDirectory, + targetFileName + ".teavmdbg"))) { + debugInfo.write(debugInfoOut); + } + log.info("Debug information successfully written"); + } + if (sourceMapsFileGenerated) { + assert debugEmitter != null; + DebugInformation debugInfo = debugEmitter.getDebugInformation(); + String sourceMapsFileName = targetFileName + ".map"; + writer.append("\n//# sourceMappingURL=").append(sourceMapsFileName); + try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream( + new File(targetDirectory, sourceMapsFileName)), "UTF-8")) { + debugInfo.writeAsSourceMaps(sourceMapsOut, "src", targetFileName); + } + log.info("Source maps successfully written"); + } + if (sourceFilesCopied) { + copySourceFiles(); + log.info("Source files successfully written"); + } + + if (runtime == RuntimeCopyOperation.SEPARATE) { + resourceToFile("org/teavm/javascript/runtime.js", "runtime.js"); + } + if (mainPageIncluded) { + String text; + try (Reader reader = new InputStreamReader(classLoader.getResourceAsStream( + "org/teavm/tooling/main.html"), "UTF-8")) { + text = IOUtils.toString(reader).replace("${classes.js}", targetFileName); + } + File mainPageFile = new File(targetDirectory, "main.html"); + try (Writer mainPageWriter = new OutputStreamWriter(new FileOutputStream(mainPageFile), "UTF-8")) { + mainPageWriter.append(text); + } + } + } + private void copySourceFiles() { if (vm.getWrittenClasses() == null) { return; diff --git a/tools/core/teavm-tooling.iml b/tools/core/teavm-tooling.iml index a636e0d00..45225ea38 100644 --- a/tools/core/teavm-tooling.iml +++ b/tools/core/teavm-tooling.iml @@ -7,7 +7,7 @@ - + diff --git a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java index d8856ee71..787b559eb 100644 --- a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java +++ b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java @@ -20,8 +20,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; @@ -49,6 +47,7 @@ import org.junit.runners.model.InitializationError; import org.teavm.callgraph.CallGraph; import org.teavm.diagnostics.DefaultProblemTextConsumer; import org.teavm.diagnostics.Problem; +import org.teavm.javascript.target.JavaScriptTarget; import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolderSource; import org.teavm.model.MethodDescriptor; @@ -345,12 +344,13 @@ public class TeaVMTestRunner extends Runner { MethodHolder methodHolder = classHolder.getMethod(getDescriptor(method)); Class runnerType = testAdapter.getRunner(methodHolder); - TeaVM vm = new TeaVMBuilder() + JavaScriptTarget jsTarget = new JavaScriptTarget(); + jsTarget.setMinifying(false); + TeaVM vm = new TeaVMBuilder(jsTarget) .setClassLoader(classLoader) .setClassSource(classSource) .build(); vm.setIncremental(false); - vm.setMinifying(false); vm.installPlugins(); new TestExceptionPlugin().install(vm); @@ -360,7 +360,7 @@ public class TeaVMTestRunner extends Runner { applyProperties(method.getDeclaringClass(), properties); vm.setProperties(properties); - try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(outputFile), "UTF-8")) { + try (OutputStream innerWriter = new FileOutputStream(outputFile)) { MethodReference exceptionMsg = new MethodReference(ExceptionHelper.class, "showException", Throwable.class, String.class); vm.entryPoint("runTest", new MethodReference(TestEntryPoint.class, "run", void.class)).async(); diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java index dbc1dac6d..cc90bbc03 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java @@ -55,9 +55,6 @@ public class BuildJavascriptMojo extends AbstractJavascriptMojo { @Parameter private boolean mainPageIncluded; - @Parameter - private boolean bytecodeLogging; - @Parameter private ClassAlias[] classAliases; @@ -86,7 +83,6 @@ public class BuildJavascriptMojo extends AbstractJavascriptMojo { setupTool(tool); tool.setLog(new MavenTeaVMToolLog(log)); try { - tool.setBytecodeLogging(bytecodeLogging); tool.setMainClass(mainClass); tool.setMainPageIncluded(mainPageIncluded); tool.setRuntime(runtime);