diff --git a/teavm-cli/src/main/java/org/teavm/cli/TeaVMRunner.java b/teavm-cli/src/main/java/org/teavm/cli/TeaVMRunner.java index d14073f9d..190309403 100644 --- a/teavm-cli/src/main/java/org/teavm/cli/TeaVMRunner.java +++ b/teavm-cli/src/main/java/org/teavm/cli/TeaVMRunner.java @@ -65,6 +65,19 @@ public final class TeaVMRunner { .withDescription("Generate debug information") .withLongOpt("debug") .create('D')); + options.addOption(OptionBuilder + .withDescription("Generate source maps") + .withLongOpt("sourcemaps") + .create('S')); + options.addOption(OptionBuilder + .withDescription("Incremental build") + .withLongOpt("incremental") + .create('i')); + options.addOption(OptionBuilder + .withArgName("directory") + .withDescription("Incremental build cache directory") + .withLongOpt("cachedir") + .create('c')); options.addOption(OptionBuilder .withDescription("Generate source maps") .withLongOpt("sourcemaps") @@ -117,10 +130,16 @@ public final class TeaVMRunner { tool.setMainPageIncluded(true); } if (commandLine.hasOption('D')) { - tool.setDebugInformation(new File(tool.getTargetDirectory(), tool.getTargetFileName() + ".teavmdbg")); - if (commandLine.hasOption("sourcemaps")) { - tool.setSourceMapsFileGenerated(true); - } + tool.setDebugInformationGenerated(true); + } + if (commandLine.hasOption('S')) { + tool.setSourceMapsFileGenerated(true); + } + if (commandLine.hasOption('i')) { + tool.setIncremental(true); + } + if (commandLine.hasOption('c')) { + tool.setCacheDirectory(new File(commandLine.getOptionValue('c'))); } args = commandLine.getArgs(); if (args.length > 1) { diff --git a/teavm-core/src/main/java/org/teavm/cache/FileProgramCache.java b/teavm-core/src/main/java/org/teavm/cache/FileProgramCache.java deleted file mode 100644 index f47676ecf..000000000 --- a/teavm-core/src/main/java/org/teavm/cache/FileProgramCache.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.cache; - -import org.teavm.model.MethodReference; -import org.teavm.model.Program; -import org.teavm.model.ProgramCache; - -/** - * - * @author Alexey Andreev - */ -public class FileProgramCache implements ProgramCache { - - @Override - public Program get(MethodReference method) { - return null; - } - - @Override - public void store(MethodReference method, Program program) { - } -} diff --git a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java index e60bd62c0..ef1ca0d9a 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -20,13 +20,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.apache.commons.io.IOUtils; +import org.teavm.cache.DiskCachedClassHolderSource; +import org.teavm.cache.DiskProgramCache; +import org.teavm.cache.DiskRegularMethodNodeCache; +import org.teavm.cache.FileSymbolTable; import org.teavm.debugging.information.DebugInformation; import org.teavm.debugging.information.DebugInformationBuilder; 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.model.*; import org.teavm.parsing.ClasspathClassHolderSource; import org.teavm.vm.*; import org.teavm.vm.spi.AbstractRendererListener; @@ -44,14 +45,20 @@ public class TeaVMTool { private Properties properties = new Properties(); private boolean mainPageIncluded; private boolean bytecodeLogging; - private File debugInformation; - private String sourceMapsFileName; + private boolean debugInformationGenerated; private boolean sourceMapsFileGenerated; + private boolean incremental; + private File cacheDirectory = new File("./teavm-cache"); private List transformers = new ArrayList<>(); private List classAliases = new ArrayList<>(); private List methodAliases = new ArrayList<>(); private TeaVMToolLog log = new EmptyTeaVMToolLog(); private ClassLoader classLoader = TeaVMTool.class.getClassLoader(); + private DiskCachedClassHolderSource cachedClassSource; + private DiskProgramCache programCache; + private DiskRegularMethodNodeCache astCache; + private FileSymbolTable symbolTable; + private FileSymbolTable fileTable; public File getTargetDirectory() { return targetDirectory; @@ -77,6 +84,14 @@ public class TeaVMTool { this.minifying = minifying; } + public boolean isIncremental() { + return incremental; + } + + public void setIncremental(boolean incremental) { + this.incremental = incremental; + } + public String getMainClass() { return mainClass; } @@ -109,20 +124,20 @@ public class TeaVMTool { this.bytecodeLogging = bytecodeLogging; } - public File getDebugInformation() { - return debugInformation; + public boolean isDebugInformationGenerated() { + return debugInformationGenerated; } - public void setDebugInformation(File debugInformation) { - this.debugInformation = debugInformation; + public void setDebugInformationGenerated(boolean debugInformationGenerated) { + this.debugInformationGenerated = debugInformationGenerated; } - public String getSourceMapsFileName() { - return sourceMapsFileName; + public File getCacheDirectory() { + return cacheDirectory; } - public void setSourceMapsFileName(String sourceMapsFileName) { - this.sourceMapsFileName = sourceMapsFileName; + public void setCacheDirectory(File cacheDirectory) { + this.cacheDirectory = cacheDirectory; } public boolean isSourceMapsFileGenerated() { @@ -169,13 +184,38 @@ public class TeaVMTool { try { log.info("Building JavaScript file"); TeaVMBuilder vmBuilder = new TeaVMBuilder(); - vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader)); + if (incremental) { + cacheDirectory.mkdirs(); + symbolTable = new FileSymbolTable(new File(cacheDirectory, "symbols")); + fileTable = new FileSymbolTable(new File(cacheDirectory, "files")); + ClasspathClassHolderSource innerClassSource = new ClasspathClassHolderSource(classLoader); + ClassHolderSource classSource = new PreOptimizingClassHolderSource(innerClassSource); + cachedClassSource = new DiskCachedClassHolderSource(cacheDirectory, symbolTable, fileTable, + classSource, innerClassSource); + programCache = new DiskProgramCache(cacheDirectory, symbolTable, fileTable, innerClassSource); + astCache = new DiskRegularMethodNodeCache(cacheDirectory, symbolTable, fileTable, innerClassSource); + try { + symbolTable.update(); + fileTable.update(); + } catch (IOException e) { + log.info("Cache was not read"); + } + vmBuilder.setClassLoader(classLoader).setClassSource(cachedClassSource); + } else { + vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader)); + } TeaVM vm = vmBuilder.build(); vm.setMinifying(minifying); vm.setBytecodeLogging(bytecodeLogging); vm.setProperties(properties); - DebugInformationBuilder debugEmitter = debugInformation != null ? new DebugInformationBuilder() : null; + DebugInformationBuilder debugEmitter = debugInformationGenerated || sourceMapsFileGenerated ? + new DebugInformationBuilder() : null; vm.setDebugEmitter(debugEmitter); + vm.setIncremental(incremental); + if (incremental) { + vm.setAstCache(astCache); + vm.setProgramCache(programCache); + } vm.installPlugins(); for (ClassHolderTransformer transformer : transformers) { vm.add(transformer); @@ -215,24 +255,32 @@ public class TeaVMTool { vm.build(writer, new DirectoryBuildTarget(targetDirectory)); vm.checkForMissingItems(); log.info("JavaScript file successfully built"); - if (debugInformation != null) { + if (debugInformationGenerated) { DebugInformation debugInfo = debugEmitter.getDebugInformation(); - try (OutputStream debugInfoOut = new FileOutputStream(debugInformation)) { + try (OutputStream debugInfoOut = new FileOutputStream(new File(targetDirectory, + targetFileName + ".teavmdbg"))) { debugInfo.write(debugInfoOut); } log.info("Debug information successfully written"); - if (sourceMapsFileGenerated) { - String sourceMapsFileName = this.sourceMapsFileName; - if (sourceMapsFileName == null) { - 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, targetFileName); - } - log.info("Source maps successfully written"); + } + if (sourceMapsFileGenerated) { + 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, targetFileName); } + log.info("Source maps successfully written"); + } + if (incremental) { + programCache.flush(); + astCache.flush(); + cachedClassSource.flush(); + symbolTable.flush(); + fileTable.flush(); + log.info(mainClass); + log.info("Cache updated"); } } if (runtime == RuntimeCopyOperation.SEPARATE) { 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 c81771ccf..3a7d431e2 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 @@ -78,7 +78,13 @@ public class BuildJavascriptMojo extends AbstractMojo { private boolean debugInformationGenerated; @Parameter - private File debugInformationFile; + private boolean sourceMapsGenerated; + + @Parameter + private boolean incremental; + + @Parameter(defaultValue = "${project.build.directory}/teavm-cache") + private File cacheDirectory; @Parameter private String[] transformers; @@ -151,12 +157,28 @@ public class BuildJavascriptMojo extends AbstractMojo { this.debugInformationGenerated = debugInformationGenerated; } - public File getDebugInformationFile() { - return debugInformationFile; + public boolean isSourceMapsGenerated() { + return sourceMapsGenerated; } - public void setDebugInformationFile(File debugInformationFile) { - this.debugInformationFile = debugInformationFile; + public void setSourceMapsGenerated(boolean sourceMapsGenerated) { + this.sourceMapsGenerated = sourceMapsGenerated; + } + + public boolean isIncremental() { + return incremental; + } + + public void setIncremental(boolean incremental) { + this.incremental = incremental; + } + + public File getCacheDirectory() { + return cacheDirectory; + } + + public void setCacheDirectory(File cacheDirectory) { + this.cacheDirectory = cacheDirectory; } @Override @@ -183,10 +205,10 @@ public class BuildJavascriptMojo extends AbstractMojo { if (properties != null) { tool.getProperties().putAll(properties); } - if (isDebugInformationGenerated()) { - tool.setDebugInformation(debugInformationFile != null ? debugInformationFile : - new File(targetDirectory, targetFileName + ".teavmdbg")); - } + tool.setCacheDirectory(cacheDirectory); + tool.setIncremental(incremental); + tool.setDebugInformationGenerated(debugInformationGenerated); + tool.setSourceMapsFileGenerated(sourceMapsGenerated); tool.generate(); } catch (RuntimeException e) { throw new MojoExecutionException("Unexpected error occured", e); diff --git a/teavm-samples/pom.xml b/teavm-samples/pom.xml index 351a7c08d..83f3598ae 100644 --- a/teavm-samples/pom.xml +++ b/teavm-samples/pom.xml @@ -68,6 +68,7 @@ org.teavm.samples.HelloWorld true true + true ${project.build.directory}/javascript/hello @@ -82,6 +83,7 @@ org.teavm.samples.MatrixMultiplication true true + true ${project.build.directory}/javascript/matrix @@ -96,6 +98,7 @@ org.teavm.samples.DateTime ${project.build.directory}/javascript/datetime true + true en_US,en_GB,ru_RU,ru_UA,nl_NL,nl_BE