diff --git a/build.xml b/build.xml index 6ef2272dc24..f1084a2b0b9 100644 --- a/build.xml +++ b/build.xml @@ -117,6 +117,8 @@ + + @@ -200,6 +202,8 @@ + + diff --git a/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt index d6b863930e3..1850cafdaa6 100644 --- a/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt +++ b/compiler/rmi/kotlinr/src/org/jetbrains/kotlin/rmi/kotlinr/KotlinCompilerClient.kt @@ -26,12 +26,7 @@ import java.rmi.Remote import java.rmi.registry.LocateRegistry import java.util.concurrent.Semaphore import java.util.concurrent.TimeUnit -import java.util.concurrent.locks.ReentrantReadWriteLock -import kotlin.concurrent.read import kotlin.concurrent.thread -import kotlin.concurrent.write -import kotlin.platform.platformStatic -import kotlin.reflect.KProperty1 fun Process.isAlive() = try { @@ -71,7 +66,7 @@ public class KotlinCompilerClient { } - private fun startDaemon(compilerId: CompilerId, daemonLaunchingOptions: DaemonLaunchingOptions, daemonOptions: DaemonOptions, errStream: PrintStream) { + private fun startDaemon(compilerId: CompilerId, daemonJVMOptions: DaemonJVMOptions, daemonOptions: DaemonOptions, errStream: PrintStream) { val javaExecutable = File(System.getProperty("java.home"), "bin").let { val javaw = File(it, "javaw.exe") if (javaw.exists()) javaw @@ -80,10 +75,10 @@ public class KotlinCompilerClient { // TODO: add some specific environment variables to the cp and may be command line, to allow some specific startup configs val args = listOf(javaExecutable.absolutePath, "-cp", compilerId.compilerClasspath.joinToString(File.pathSeparator)) + - daemonLaunchingOptions.extractors.flatMap { it.extract("-") } + + daemonJVMOptions.mappers.flatMap { it.toArgs("-") } + COMPILER_DAEMON_CLASS_FQN + - daemonOptions.extractors.flatMap { it.extract(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) } + - compilerId.extractors.flatMap { it.extract(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) } + daemonOptions.mappers.flatMap { it.toArgs(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) } + + compilerId.mappers.flatMap { it.toArgs(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) } errStream.println("[daemon client] starting the daemon as: " + args.joinToString(" ")) val processBuilder = ProcessBuilder(args).redirectErrorStream(true) // assuming daemon process is deaf and (mostly) silent, so do not handle streams @@ -135,14 +130,14 @@ public class KotlinCompilerClient { (localId.compilerDigest.isEmpty() || remoteId.compilerDigest.isEmpty() || localId.compilerDigest == remoteId.compilerDigest) } - public fun connectToCompileService(compilerId: CompilerId, daemonLaunchingOptions: DaemonLaunchingOptions, daemonOptions: DaemonOptions, errStream: PrintStream, autostart: Boolean = true, checkId: Boolean = true): CompileService? { + public fun connectToCompileService(compilerId: CompilerId, daemonJVMOptions: DaemonJVMOptions, daemonOptions: DaemonOptions, errStream: PrintStream, autostart: Boolean = true, checkId: Boolean = true): CompileService? { val service = connectToService(compilerId, daemonOptions, errStream) if (service != null) { if (!checkId || checkCompilerId(service, compilerId, errStream)) { errStream.println("[daemon client] found the suitable daemon") return service } - errStream.println("[daemon client] compiler identity don't match: " + compilerId.extractors.flatMap { it.extract("") }.joinToString(" ")) + errStream.println("[daemon client] compiler identity don't match: " + compilerId.mappers.flatMap { it.toArgs("") }.joinToString(" ")) if (!autostart) return null; errStream.println("[daemon client] shutdown the daemon") service.shutdown() @@ -155,13 +150,13 @@ public class KotlinCompilerClient { else errStream.println("[daemon client] cannot connect to Compile Daemon, trying to start") } - startDaemon(compilerId, daemonLaunchingOptions, daemonOptions, errStream) + startDaemon(compilerId, daemonJVMOptions, daemonOptions, errStream) errStream.println("[daemon client] daemon started, trying to connect") return connectToService(compilerId, daemonOptions, errStream) } public fun shutdownCompileService(daemonOptions: DaemonOptions): Unit { - KotlinCompilerClient.connectToCompileService(CompilerId(), DaemonLaunchingOptions(), daemonOptions, System.out, autostart = false, checkId = false) + KotlinCompilerClient.connectToCompileService(CompilerId(), DaemonJVMOptions(), daemonOptions, System.out, autostart = false, checkId = false) ?.shutdown() } @@ -196,20 +191,17 @@ public class KotlinCompilerClient { data class ClientOptions( public var stop: Boolean = false - ) :CmdlineParams { - override val extractors: List> - get() = listOf( BoolPropExtractor(this, ::stop)) - - override val parsers: List> - get() = listOf( BoolPropParser(this, ::stop)) + ) : OptionsGroup { + override val mappers: List> + get() = listOf( BoolPropMapper(this, ::stop)) } - platformStatic public fun main(vararg args: String) { + jvmStatic public fun main(vararg args: String) { val compilerId = CompilerId() val daemonOptions = DaemonOptions() - val daemonLaunchingOptions = DaemonLaunchingOptions() + val daemonLaunchingOptions = DaemonJVMOptions() val clientOptions = ClientOptions() - val filteredArgs = args.asIterable().filterSetProps(compilerId, daemonOptions, daemonLaunchingOptions, clientOptions, prefix = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) + val filteredArgs = args.asIterable().filterExtractProps(compilerId, daemonOptions, daemonLaunchingOptions, clientOptions, prefix = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) if (!clientOptions.stop) { if (compilerId.compilerClasspath.none()) { diff --git a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt index 80c6302de7d..815ea746007 100644 --- a/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt +++ b/compiler/rmi/rmi-interface/src/org/jetbrains/kotlin/rmi/DaemonParams.kt @@ -21,9 +21,7 @@ import java.io.Serializable import java.lang.management.ManagementFactory import java.security.DigestInputStream import java.security.MessageDigest -import kotlin.platform.platformStatic import kotlin.reflect.KMutableProperty1 -import kotlin.reflect.KProperty1 public val COMPILER_JAR_NAME: String = "kotlin-compiler.jar" @@ -34,85 +32,147 @@ public val COMPILE_DAEMON_ENABLED_PROPERTY: String ="kotlin.daemon.enabled" public val COMPILE_DAEMON_JVM_OPTIONS_PROPERTY: String ="kotlin.daemon.jvm.options" public val COMPILE_DAEMON_OPTIONS_PROPERTY: String ="kotlin.daemon.options" public val COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX: String ="--daemon-" +public val COMPILE_DAEMON_TIMEOUT_INFINITE_S: Int = 0 +public val COMPILE_DAEMON_MEMORY_THRESHOLD_INFINITE: Long = 0L +val COMPILER_ID_DIGEST = "MD5" -open class PropExtractor>(val dest: C, - val prop: P, - val name: String, - val convert: ((v: V) -> String?) = { it.toString() }, - val skipIf: ((v: V) -> Boolean) = { false }, - val mergeWithDelimiter: String? = null) +//open class PropExtractor>(val dest: C, +// val prop: P, +// val name: String, +// val convert: ((v: V) -> String?) = { it.toString() }, +// val skipIf: ((v: V) -> Boolean) = { false }, +// val mergeWithDelimiter: String? = null) +//{ +// constructor(dest: C, prop: P, convert: ((v: V) -> String?) = { it.toString() }, skipIf: ((v: V) -> Boolean) = { false }) : this(dest, prop, prop.name, convert, skipIf) +// open fun extract(prefix: String = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX): List = +// when { +// skipIf(prop.get(dest)) -> listOf() +// mergeWithDelimiter != null -> listOf(prefix + name + mergeWithDelimiter + convert(prop.get(dest))).filterNotNull() +// else -> listOf(prefix + name, convert(prop.get(dest))).filterNotNull() +// } +//} +// +//class BoolPropExtractor>(dest: C, prop: P, name: String? = null) +// : PropExtractor(dest, prop, name ?: prop.name, convert = { null }, skipIf = { !prop.get(dest) }) +// +//class RestPropExtractor>>(dest: C, prop: P) : PropExtractor, P>(dest, prop, convert = { null }) { +// override fun extract(prefix: String): List = prop.get(dest).map { prefix + it } +//} +// +// +//open class PropParser>(val dest: C, +// val prop: P, alternativeNames: List, +// val parse: (s: String) -> V, +// val allowMergedArg: Boolean = false) { +// val names = listOf(prop.name) + alternativeNames +// constructor(dest: C, prop: P, parse: (s: String) -> V, allowMergedArg: Boolean = false) : this(dest, prop, listOf(), parse, allowMergedArg) +// fun apply(s: String) = prop.set(dest, parse(s)) +//} +// +//class BoolPropParser>(dest: C, prop: P): PropParser(dest, prop, { true }) +// +//class RestPropParser>>(dest: C, prop: P): PropParser, P>(dest, prop, { arrayListOf() }) { +// fun add(s: String) { prop.get(dest).add(s) } +//} + +// -------------------------------------------------------- + +open class PropMapper>(val dest: C, + val prop: P, + val names: List = listOf(prop.name), + val fromString: (s: String) -> V, + val toString: ((v: V) -> String?) = { it.toString() }, + val skipIf: ((v: V) -> Boolean) = { false }, + val mergeDelimiter: String? = null) { - constructor(dest: C, prop: P, convert: ((v: V) -> String?) = { it.toString() }, skipIf: ((v: V) -> Boolean) = { false }) : this(dest, prop, prop.name, convert, skipIf) - open fun extract(prefix: String = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX): List = + open fun toArgs(prefix: String = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX): List = when { skipIf(prop.get(dest)) -> listOf() - mergeWithDelimiter != null -> listOf(prefix + name + mergeWithDelimiter + convert(prop.get(dest))).filterNotNull() - else -> listOf(prefix + name, convert(prop.get(dest))).filterNotNull() + mergeDelimiter != null -> listOf(prefix + names.first() + mergeDelimiter + toString(prop.get(dest))).filterNotNull() + else -> listOf(prefix + names.first(), toString(prop.get(dest))).filterNotNull() } + fun apply(s: String) = prop.set(dest, fromString(s)) } -class BoolPropExtractor>(dest: C, prop: P, name: String? = null) - : PropExtractor(dest, prop, name ?: prop.name, convert = { null }, skipIf = { !prop.get(dest) }) +class StringPropMapper>(dest: C, + prop: P, + names: List = listOf(), + fromString: ((String) -> String) = { it }, + toString: ((String) -> String?) = { it.toString() }, + skipIf: ((String) -> Boolean) = { it.isEmpty() }, + mergeDelimiter: String? = null) +: PropMapper(dest = dest, prop = prop, names = if (names.any()) names else listOf(prop.name), + fromString = fromString, toString = toString, skipIf = skipIf, mergeDelimiter = mergeDelimiter) -class RestPropExtractor>>(dest: C, prop: P) : PropExtractor, P>(dest, prop, convert = { null }) { - override fun extract(prefix: String): List = prop.get(dest).map { prefix + it } -} +class BoolPropMapper>(dest: C, prop: P, names: List = listOf()) + : PropMapper(dest = dest, prop = prop, names = if (names.any()) names else listOf(prop.name), + fromString = { true }, toString = { null }, skipIf = { !prop.get(dest) }) - -open class PropParser>(val dest: C, - val prop: P, alternativeNames: List, - val parse: (s: String) -> V, - val allowMergedArg: Boolean = false) { - val names = listOf(prop.name) + alternativeNames - constructor(dest: C, prop: P, parse: (s: String) -> V, allowMergedArg: Boolean = false) : this(dest, prop, listOf(), parse, allowMergedArg) - fun apply(s: String) = prop.set(dest, parse(s)) -} - -class BoolPropParser>(dest: C, prop: P): PropParser(dest, prop, { true }) - -class RestPropParser>>(dest: C, prop: P): PropParser, P>(dest, prop, { arrayListOf() }) { +class RestPropMapper>>(dest: C, prop: P) + : PropMapper, P>(dest = dest, prop = prop, toString = { null }, fromString = { arrayListOf() }) +{ + override fun toArgs(prefix: String): List = prop.get(dest).map { prefix + it } fun add(s: String) { prop.get(dest).add(s) } } +// ------------------------------------------ -fun Iterable.filterSetProps(parsers: List>, prefix: String, restParser: RestPropParser<*,*>? = null) : Iterable { - var currentParser: PropParser<*,*,*>? = null +fun Iterable.filterExtractProps(propMappers: List>, prefix: String, restParser: RestPropMapper<*,*>? = null) : Iterable { + var currentPropMapper: PropMapper<*,*,*>? = null var matchingOption = "" val res = filter { param -> - if (currentParser == null) { - val parser = parsers.find { it.names.any { name -> - if (param.startsWith(prefix + name)) { matchingOption = prefix + name; true } - else false } } - if (parser != null) { - val optionLength = matchingOption.length() - when { - parser is BoolPropParser<*,*> -> - if (param.length() > optionLength) throw IllegalArgumentException("Invalid switch option '$param', expecting $matchingOption without arguments") - else parser.apply("") - param.length() > optionLength -> - if (param[optionLength] != '=') { - if (parser.allowMergedArg) parser.apply(param.substring(optionLength)) - else throw IllegalArgumentException("Invalid option syntax '$param', expecting $matchingOption[= ]") - } - else parser.apply(param.substring(optionLength + 1)) - else -> currentParser = parser + if (currentPropMapper == null) { + val propMapper = propMappers.find { + it !is RestPropMapper<*,*> && + it.names.any { name -> + if (param.startsWith(prefix + name)) { + matchingOption = prefix + name + true + } + else { + false + } } - false } - else if (restParser != null && param.startsWith(prefix)) { - restParser.add(param.removePrefix(prefix)) - false + when { + propMapper != null -> { + val optionLength = matchingOption.length() + when { + propMapper is BoolPropMapper<*,*> -> { + if (param.length() > optionLength) + throw IllegalArgumentException("Invalid switch option '$param', expecting $matchingOption without arguments") + propMapper.apply("") + } + param.length() > optionLength -> + if (param[optionLength] != '=') { + if (propMapper.mergeDelimiter == null) + throw IllegalArgumentException("Invalid option syntax '$param', expecting $matchingOption[= ]") + propMapper.apply(param.substring(optionLength)) + } + else { + propMapper.apply(param.substring(optionLength + 1)) + } + else -> + currentPropMapper = propMapper + } + false + } + restParser != null && param.startsWith(prefix) -> { + restParser.add(param.removePrefix(prefix)) + false + } + else -> true } - else true } else { - currentParser!!.apply(param) - currentParser = null + currentPropMapper!!.apply(param) + currentPropMapper = null false } } - if (currentParser != null) throw IllegalArgumentException("Expecting argument for the option $matchingOption") + if (currentPropMapper != null) + throw IllegalArgumentException("Expecting argument for the option $matchingOption") return res } @@ -124,59 +184,46 @@ fun Iterable.filterSetProps(parsers: List>, prefix: St -public interface CmdlineParams : Serializable { - public val extractors: List> - public val parsers: List> +public interface OptionsGroup : Serializable { + public val mappers: List> } -public fun Iterable.filterSetProps(vararg cs: CmdlineParams, prefix: String) : Iterable = - filterSetProps(cs.flatMap { it.parsers }, prefix) +public fun Iterable.filterExtractProps(vararg groups: OptionsGroup, prefix: String) : Iterable = + filterExtractProps(groups.flatMap { it.mappers }, prefix) -public data class DaemonLaunchingOptions( +public data class DaemonJVMOptions( public var maxMemory: String = "", public var maxPermSize: String = "", public var reservedCodeCacheSize: String = "", public var otherJvmParams: MutableCollection = arrayListOf() -) : CmdlineParams { +) : OptionsGroup { - override val extractors: List> - get() = listOf( PropExtractor(this, ::maxMemory, "Xmx", skipIf = { it.isEmpty() }, mergeWithDelimiter = ""), - PropExtractor(this, ::maxPermSize, "XX:MaxPermSize", skipIf = { it.isEmpty() }, mergeWithDelimiter = "="), - PropExtractor(this, ::reservedCodeCacheSize, "XX:ReservedCodeCacheSize", skipIf = { it.isEmpty() }, mergeWithDelimiter = "="), - RestPropExtractor(this, ::otherJvmParams)) + override val mappers: List> + get() = listOf( StringPropMapper(this, ::maxMemory, listOf("Xmx"), mergeDelimiter = ""), + StringPropMapper(this, ::maxPermSize, listOf("XX:MaxPermSize"), mergeDelimiter = "="), + StringPropMapper(this, ::reservedCodeCacheSize, listOf("XX:ReservedCodeCacheSize"), mergeDelimiter = "="), + restMapper) - override val parsers: List> - get() = listOf( PropParser(this, ::maxMemory, listOf("Xmx"), { it }, allowMergedArg = true), - PropParser(this, ::maxPermSize, listOf("XX:MaxPermSize"), { it }, allowMergedArg = true), - PropParser(this, ::reservedCodeCacheSize, listOf("XX:ReservedCodeCacheSize"), { it }, allowMergedArg = true)) - // otherJvmParams is missing here deliberately, it is used explicitly as a restParser param to filterSetProps + val restMapper: RestPropMapper<*,*> + get() = RestPropMapper(this, ::otherJvmParams) } public data class DaemonOptions( public var port: Int = COMPILE_DAEMON_DEFAULT_PORT, - public var autoshutdownMemoryThreshold: Long = 0 /* 0 means unchecked */, - public var autoshutdownIdleSeconds: Int = 0 /* 0 means unchecked */, + public var autoshutdownMemoryThreshold: Long = COMPILE_DAEMON_MEMORY_THRESHOLD_INFINITE, + public var autoshutdownIdleSeconds: Int = COMPILE_DAEMON_TIMEOUT_INFINITE_S, public var startEcho: String = COMPILER_SERVICE_RMI_NAME -) : CmdlineParams { +) : OptionsGroup { - override val extractors: List> - get() = listOf( PropExtractor(this, ::port), - PropExtractor(this, ::autoshutdownMemoryThreshold, skipIf = { it == 0L }), - PropExtractor(this, ::autoshutdownIdleSeconds, skipIf = { it == 0 }), - PropExtractor(this, ::startEcho)) - - override val parsers: List> - get() = listOf( PropParser(this, ::port, { it.toInt()}), - PropParser(this, ::autoshutdownMemoryThreshold, { it.toLong()}), - PropParser(this, ::autoshutdownIdleSeconds, { it.toInt()}), - PropParser(this, ::startEcho, { it.trim('"') })) + override val mappers: List> + get() = listOf( PropMapper(this, ::port, fromString = { it.toInt() }), + PropMapper(this, ::autoshutdownMemoryThreshold, fromString = { it.toLong() }, skipIf = { it == 0L }), + PropMapper(this, ::autoshutdownIdleSeconds, fromString = { it.toInt() }, skipIf = { it == 0 }), + PropMapper(this, ::startEcho, fromString = { it.trim('"') })) } -val COMPILER_ID_DIGEST = "MD5" - - fun updateSingleFileDigest(file: File, md: MessageDigest) { DigestInputStream(file.inputStream(), md).use { val buf = ByteArray(1024) @@ -215,27 +262,21 @@ public data class CompilerId( public var compilerDigest: String = "", public var compilerVersion: String = "" // TODO: checksum -) : CmdlineParams { +) : OptionsGroup { - override val extractors: List> - get() = listOf( PropExtractor(this, ::compilerClasspath, convert = { it.joinToString(File.pathSeparator) }), - PropExtractor(this, ::compilerDigest), - PropExtractor(this, ::compilerVersion, skipIf = { it.isEmpty() })) - - override val parsers: List> - get() = - listOf( PropParser(this, ::compilerClasspath, { it.trim('"').split(File.pathSeparator)}), - PropParser(this, ::compilerDigest, { it.trim('"') }), - PropParser(this, ::compilerVersion, { it.trim('"') })) + override val mappers: List> + get() = listOf( PropMapper(this, ::compilerClasspath, toString = { it.joinToString(File.pathSeparator) }, fromString = { it.trim('"').split(File.pathSeparator)}), + StringPropMapper(this, ::compilerDigest), + StringPropMapper(this, ::compilerVersion)) public fun updateDigest() { compilerDigest = compilerClasspath.getClasspathDigest() } companion object { - public platformStatic fun makeCompilerId(vararg paths: File): CompilerId = makeCompilerId(paths.asIterable()) + public jvmStatic fun makeCompilerId(vararg paths: File): CompilerId = makeCompilerId(paths.asIterable()) - public platformStatic fun makeCompilerId(paths: Iterable): CompilerId = + public jvmStatic fun makeCompilerId(paths: Iterable): CompilerId = // TODO consider reading version here CompilerId(compilerClasspath = paths.map { it.absolutePath }, compilerDigest = paths.getFilesClasspathDigest()) } @@ -245,27 +286,27 @@ public data class CompilerId( public fun isDaemonEnabled(): Boolean = System.getProperty(COMPILE_DAEMON_ENABLED_PROPERTY) != null -public fun configureDaemonLaunchingOptions(opts: DaemonLaunchingOptions, inheritMemoryLimits: Boolean): DaemonLaunchingOptions { +public fun configureDaemonLaunchingOptions(opts: DaemonJVMOptions, inheritMemoryLimits: Boolean): DaemonJVMOptions { // note: sequence matters, explicit override in COMPILE_DAEMON_JVM_OPTIONS_PROPERTY should be done after inputArguments processing if (inheritMemoryLimits) - ManagementFactory.getRuntimeMXBean().inputArguments.filterSetProps(opts.parsers, "-") + ManagementFactory.getRuntimeMXBean().inputArguments.filterExtractProps(opts.mappers, "-") System.getProperty(COMPILE_DAEMON_JVM_OPTIONS_PROPERTY)?.let { - opts.otherJvmParams.addAll( it.trim('"', '\'').split(",").filterSetProps(opts.parsers, "-", RestPropParser(opts, DaemonLaunchingOptions::otherJvmParams))) + opts.otherJvmParams.addAll( it.trim('"', '\'').split(",").filterExtractProps(opts.mappers, "-", opts.restMapper)) } return opts } -public fun configureDaemonLaunchingOptions(inheritMemoryLimits: Boolean): DaemonLaunchingOptions = - configureDaemonLaunchingOptions(DaemonLaunchingOptions(), inheritMemoryLimits = inheritMemoryLimits) +public fun configureDaemonLaunchingOptions(inheritMemoryLimits: Boolean): DaemonJVMOptions = + configureDaemonLaunchingOptions(DaemonJVMOptions(), inheritMemoryLimits = inheritMemoryLimits) jvmOverloads public fun configureDaemonOptions(opts: DaemonOptions = DaemonOptions()): DaemonOptions { System.getProperty(COMPILE_DAEMON_OPTIONS_PROPERTY)?.let { - val unrecognized = it.trim('"', '\'').split(",").filterSetProps(opts.parsers, "") + val unrecognized = it.trim('"', '\'').split(",").filterExtractProps(opts.mappers, "") if (unrecognized.any()) throw IllegalArgumentException( "Unrecognized daemon options passed via property $COMPILE_DAEMON_OPTIONS_PROPERTY: " + unrecognized.joinToString(" ") + - "\nSupported options: " + opts.extractors.joinToString(", ", transform = { it.name })) + "\nSupported options: " + opts.mappers.joinToString(", ", transform = { it.names.first() })) } return opts } diff --git a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileDaemon.kt b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileDaemon.kt index 3c274d52f72..84c70919de2 100644 --- a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileDaemon.kt +++ b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileDaemon.kt @@ -17,10 +17,7 @@ package org.jetbrains.kotlin.rmi.service import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler -import org.jetbrains.kotlin.rmi.COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX -import org.jetbrains.kotlin.rmi.CompilerId -import org.jetbrains.kotlin.rmi.DaemonOptions -import org.jetbrains.kotlin.rmi.filterSetProps +import org.jetbrains.kotlin.rmi.* import org.jetbrains.kotlin.service.CompileServiceImpl import java.io.OutputStream import java.io.PrintStream @@ -96,7 +93,7 @@ public class CompileDaemon { val compilerId = CompilerId() val daemonOptions = DaemonOptions() - val filteredArgs = args.asIterable().filterSetProps(compilerId, daemonOptions, prefix = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) + val filteredArgs = args.asIterable().filterExtractProps(compilerId, daemonOptions, prefix = COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) if (filteredArgs.any()) { val helpLine = "usage: " diff --git a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt index fd2b51fbaf2..f3ca7bd58a9 100644 --- a/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt +++ b/compiler/rmi/rmi-server/src/org/jetbrains/kotlin/rmi/service/CompileServiceImpl.kt @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.service import org.jetbrains.kotlin.cli.common.CLICompiler -import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache @@ -25,15 +24,12 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompil import org.jetbrains.kotlin.rmi.* import org.jetbrains.kotlin.rmi.service.RemoteIncrementalCacheClient import org.jetbrains.kotlin.rmi.service.RemoteOutputStreamClient -import java.io.File -import java.io.FileNotFoundException import java.io.IOException import java.io.PrintStream import java.lang.management.ManagementFactory import java.net.URLClassLoader import java.rmi.registry.Registry import java.rmi.server.UnicastRemoteObject -import java.util.* import java.util.concurrent.TimeUnit import java.util.concurrent.locks.ReentrantReadWriteLock import java.util.jar.Manifest @@ -86,12 +82,14 @@ class CompileServiceImpl>( public class IncrementalCompilationComponentsImpl(val idToCache: Map): IncrementalCompilationComponents { // perf: cheap object, but still the pattern may be costly if there are too many calls to cache with the same id (which seems not to be the case now) override fun getIncrementalCache(moduleId: String): IncrementalCache = RemoteIncrementalCacheClient(idToCache[moduleId]!!) + // TODO: add appropriate proxy into interaction when lookup tracker is needed override fun getLookupTracker(): LookupTracker = LookupTracker.DO_NOTHING } private fun createCompileServices(incrementalCaches: Map): Services = Services.Builder() - .register(javaClass(), IncrementalCompilationComponentsImpl(incrementalCaches)) + .register(IncrementalCompilationComponents::class.java, IncrementalCompilationComponentsImpl(incrementalCaches)) + // TODO: add remote proxy for cancellation status tracking // .register(javaClass(), object: CompilationCanceledStatus { // override fun checkCanceled(): Unit = if (context.getCancelStatus().isCanceled()) throw CompilationCanceledException() // }) @@ -111,6 +109,7 @@ class CompileServiceImpl>( return memHeap.used } + // TODO: consider using version as a part of compiler ID or drop this function private fun loadKotlinVersionFromResource(): String { (javaClass.classLoader as? URLClassLoader) ?.findResource("META-INF/MANIFEST.MF") @@ -158,6 +157,7 @@ class CompileServiceImpl>( else body() } + // sometimes used for debugging fun spy(msg: String, body: () -> R): R { val res = body() log.info(msg + " = " + res.toString()) @@ -178,26 +178,25 @@ class CompileServiceImpl>( } override fun remoteCompile(args: Array, errStream: RemoteOutputStream, outputFormat: CompileService.OutputFormat): Int = - ifAlive { - checkedCompile(args) { - val strm = RemoteOutputStreamClient(errStream) - val printStrm = PrintStream(strm) - when (outputFormat) { - CompileService.OutputFormat.PLAIN -> compiler.exec(printStrm, *args) - CompileService.OutputFormat.XML -> compiler.execAndOutputXml(printStrm, Services.EMPTY, *args) - }.code - } + doCompile(args, errStream) { printStream -> + when (outputFormat) { + CompileService.OutputFormat.PLAIN -> compiler.exec(printStream, *args) + CompileService.OutputFormat.XML -> compiler.execAndOutputXml(printStream, Services.EMPTY, *args) + }.code } - override fun remoteIncrementalCompile(args: Array, caches: Map, errStream: RemoteOutputStream, outputFormat: CompileService.OutputFormat): Int = + override fun remoteIncrementalCompile(args: Array, caches: Map, outputStream: RemoteOutputStream, outputFormat: CompileService.OutputFormat): Int = + doCompile(args, outputStream) { printStream -> + when (outputFormat) { + CompileService.OutputFormat.PLAIN -> throw NotImplementedError("Only XML output is supported in remote incremental compilation") + CompileService.OutputFormat.XML -> compiler.execAndOutputXml(printStream, createCompileServices(caches), *args) + }.code + } + + fun doCompile(args: Array, errStream: RemoteOutputStream, body: (PrintStream) -> Int): Int = ifAlive { checkedCompile(args) { - val strm = RemoteOutputStreamClient(errStream) - val printStrm = PrintStream(strm) - when (outputFormat) { - CompileService.OutputFormat.PLAIN -> throw NotImplementedError("Only XML output is supported in remote incremental compilation") - CompileService.OutputFormat.XML -> compiler.execAndOutputXml(printStrm, createCompileServices(caches), *args) - }.code + body( PrintStream( RemoteOutputStreamClient(errStream))) } } } diff --git a/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt b/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt index dd5842f9e5e..804afae51dc 100644 --- a/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/daemon/CompilerDaemonTest.kt @@ -20,7 +20,7 @@ import junit.framework.TestCase import org.jetbrains.kotlin.cli.CliBaseTest import org.jetbrains.kotlin.integration.KotlinIntegrationTestBase import org.jetbrains.kotlin.rmi.CompilerId -import org.jetbrains.kotlin.rmi.DaemonLaunchingOptions +import org.jetbrains.kotlin.rmi.DaemonJVMOptions import org.jetbrains.kotlin.rmi.DaemonOptions import org.jetbrains.kotlin.rmi.kotlinr.KotlinCompilerClient import org.jetbrains.kotlin.test.JetTestUtils @@ -34,7 +34,7 @@ public class CompilerDaemonTest : KotlinIntegrationTestBase() { data class CompilerResults(val resultCode: Int, val out: String) val daemonOptions = DaemonOptions(port = KOTLIN_DAEMON_TEST_PORT) - val daemonLaunchingOptions = DaemonLaunchingOptions() + val daemonLaunchingOptions = DaemonJVMOptions() val compilerId by lazy { CompilerId.makeCompilerId( File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-compiler.jar"), File("dependencies/bootstrap-compiler/Kotlin/kotlinc/lib/kotlin-runtime.jar"), File("dependencies/bootstrap-compiler/Kotlin/kotlinc/lib/kotlin-reflect.jar")) } diff --git a/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java b/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java index c5460c78d48..3f62f14e35b 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java +++ b/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.java @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.compilerRunner; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; @@ -136,9 +135,9 @@ public class KotlinCompilerRunner { // the lifetime of JPS process is small anyway, we can neglect the probability of changed compiler CompilerId compilerId = CompilerId.makeCompilerId(new File(libPath, "kotlin-compiler.jar")); DaemonOptions daemonOptions = RmiPackage.configureDaemonOptions(); - DaemonLaunchingOptions daemonLaunchingOptions = RmiPackage.configureDaemonLaunchingOptions(true); + DaemonJVMOptions daemonJVMOptions = RmiPackage.configureDaemonLaunchingOptions(true); // TODO: find proper stream to report daemon connection progress - CompileService daemon = KotlinCompilerClient.Companion.connectToCompileService(compilerId, daemonLaunchingOptions, daemonOptions, System.out, true, true); + CompileService daemon = KotlinCompilerClient.Companion.connectToCompileService(compilerId, daemonJVMOptions, daemonOptions, System.out, true, true); if (daemon != null) { Integer res = KotlinCompilerClient.Companion.incrementalCompile(daemon, argsArray, incrementalCaches, out); return res.toString();