Implement JS IC

This commit is contained in:
Alexey Tsvetkov
2017-08-29 00:07:44 +03:00
parent 4aea9b349c
commit bb1cba67b7
12 changed files with 417 additions and 11 deletions
@@ -17,5 +17,6 @@
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="util" />
<orderEntry type="library" name="junit-4.12" level="project" />
<orderEntry type="module" module-name="js.frontend" />
</component>
</module>
@@ -75,4 +75,13 @@ class IncrementalJvmCachesManager(
private val jvmCacheDir = File(cacheDirectory, "jvm").apply { mkdirs() }
override val platformCache = IncrementalCacheImpl(jvmCacheDir, outputDir).apply { registerCache() }
}
class IncrementalJsCachesManager(
cachesRootDir: File,
reporter: ICReporter
) : IncrementalCachesManager<IncrementalJsCache>(cachesRootDir, reporter) {
private val jsCacheFile = File(cachesRootDir, "js").apply { mkdirs() }
override val platformCache = IncrementalJsCache(jsCacheFile).apply { registerCache() }
}
@@ -0,0 +1,136 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.build.GeneratedFile
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.js.*
import java.io.File
fun makeJsIncrementally(
cachesDir: File,
sourceRoots: Iterable<File>,
args: K2JSCompilerArguments,
messageCollector: MessageCollector = MessageCollector.NONE,
reporter: ICReporter = EmptyICReporter
) {
val versions = commonCacheVersions(cachesDir) + standaloneCacheVersion(cachesDir)
val allKotlinFiles = sourceRoots.asSequence().flatMap { it.walk() }
.filter { it.isFile && it.extension.equals("kt", ignoreCase = true) }.toList()
withJsIC {
val compiler = IncrementalJsCompilerRunner(cachesDir, versions, reporter)
compiler.compile(allKotlinFiles, args, messageCollector) {
it.inputsCache.sourceSnapshotMap.compareAndUpdate(allKotlinFiles)
}
}
}
inline fun <R> withJsIC(fn: ()->R): R {
val isJsEnabledBackup = IncrementalCompilation.isEnabledForJs()
IncrementalCompilation.setIsEnabledForJs(true)
try {
return withIC { fn() }
}
finally {
IncrementalCompilation.setIsEnabledForJs(isJsEnabledBackup)
}
}
class IncrementalJsCompilerRunner(
workingDir: File,
cacheVersions: List<CacheVersion>,
reporter: ICReporter
) : IncrementalCompilerRunner<K2JSCompilerArguments, IncrementalJsCachesManager>(
workingDir,
"caches-js",
cacheVersions,
reporter,
artifactChangesProvider = null,
changesRegistry = null
) {
override fun isICEnabled(): Boolean =
IncrementalCompilation.isEnabled() && IncrementalCompilation.isEnabledForJs()
override fun createCacheManager(args: K2JSCompilerArguments): IncrementalJsCachesManager =
IncrementalJsCachesManager(cacheDirectory, reporter)
override fun destionationDir(args: K2JSCompilerArguments): File =
File(args.outputFile).parentFile
override fun calculateSourcesToCompile(caches: IncrementalJsCachesManager, changedFiles: ChangedFiles.Known, args: K2JSCompilerArguments): CompilationMode {
if (BuildInfo.read(lastBuildInfoFile) == null) return CompilationMode.Rebuild { "No information on previous build" }
return CompilationMode.Incremental(getDirtyFiles(changedFiles))
}
override fun makeServices(
args: K2JSCompilerArguments,
lookupTracker: LookupTracker,
caches: IncrementalJsCachesManager,
compilationMode: CompilationMode
): Services.Builder =
super.makeServices(args, lookupTracker, caches, compilationMode).apply {
register(IncrementalResultsConsumer::class.java, IncrementalResultsConsumerImpl())
if (compilationMode is CompilationMode.Incremental) {
register(IncrementalDataProvider::class.java, IncrementalDataProviderFromCache(caches.platformCache))
}
}
override fun updateCaches(
services: Services,
caches: IncrementalJsCachesManager,
generatedFiles: List<GeneratedFile>,
changesCollector: ChangesCollector
) {
val incrementalResults = services.get(IncrementalResultsConsumer::class.java) as IncrementalResultsConsumerImpl
val jsCache = caches.platformCache
jsCache.header = incrementalResults.headerMetadata
return jsCache.compareAndUpdate(incrementalResults.packageParts, changesCollector)
}
override fun runCompiler(
sourcesToCompile: Set<File>,
args: K2JSCompilerArguments,
caches: IncrementalJsCachesManager,
services: Services,
messageCollector: MessageCollector
): ExitCode {
val freeArgsBackup = args.freeArgs.toMutableList()
try {
sourcesToCompile.mapTo(args.freeArgs) { it.absolutePath }
val exitCode = K2JSCompiler().exec(messageCollector, services, args)
reporter.reportCompileIteration(sourcesToCompile, exitCode)
return exitCode
}
finally {
args.freeArgs = freeArgsBackup
}
}
}
@@ -65,7 +65,7 @@ fun makeIncrementally(
}
}
private object EmptyICReporter : ICReporter {
object EmptyICReporter : ICReporter {
override fun report(message: ()->String) {
}
}
@@ -92,7 +92,7 @@ class IncrementalJvmCompilerRunner(
changesRegistry: ChangesRegistry? = null
) : IncrementalCompilerRunner<K2JVMCompilerArguments, IncrementalJvmCachesManager>(
workingDir,
CACHES_DIR_NAME,
"caches-jvm",
cacheVersions,
reporter,
artifactChangesProvider,
@@ -309,10 +309,6 @@ class IncrementalJvmCompilerRunner(
moduleFile.delete()
}
}
companion object {
const val CACHES_DIR_NAME = "caches"
}
}
var K2JVMCompilerArguments.destinationAsFile: File
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.config.IncrementalCompilation
import java.io.File
internal const val STANDALONE_CACHE_VERSION = 1
internal const val STANDALONE_CACHE_VERSION = 2
internal const val STANDALONE_VERSION_FILE_NAME = "standalone-ic-format-version.txt"
fun standaloneCacheVersion(dataRoot: File): CacheVersion =
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.incremental.js
import org.jetbrains.kotlin.incremental.IncrementalJsCache
import java.io.File
internal class IncrementalDataProviderFromCache(private val cache: IncrementalJsCache) : IncrementalDataProvider {
override val headerMetadata: ByteArray
get() = cache.header
override val compiledPackageParts: Map<File, TranslationResultValue>
get() = cache.nonDirtyPackageParts()
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.incremental.utils.TestCompilationResult
import org.jetbrains.kotlin.incremental.utils.TestICReporter
import org.jetbrains.kotlin.incremental.utils.TestMessageCollector
import java.io.File
class IncrementalJsCompilerRunnerTest : IncrementalCompilerRunnerTestBase<K2JSCompilerArguments>() {
override fun make(cacheDir: File, sourceRoots: Iterable<File>, args: K2JSCompilerArguments): TestCompilationResult {
val reporter = TestICReporter()
val messageCollector = TestMessageCollector()
makeJsIncrementally(cacheDir, sourceRoots, args, reporter = reporter, messageCollector = messageCollector)
return TestCompilationResult(reporter, messageCollector)
}
override fun createCompilerArguments(destinationDir: File, testDir: File): K2JSCompilerArguments =
K2JSCompilerArguments().apply {
outputFile = File(destinationDir, "${testDir.name}.js").path
libraries = File(bootstrapKotlincLib, "kotlin-stdlib-js.jar").path
}
}