diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index 0ab46c97123..ba5a18f1c6f 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -287,6 +287,9 @@ public class KotlinCoreEnvironment private constructor( return KotlinCoreEnvironment(parentDisposable, createApplicationEnvironment(parentDisposable, configuration, extensionConfigs), configuration) } + // used in the daemon for jar cache cleanup + public val applicationEnvironment: JavaCoreApplicationEnvironment? get() = ourApplicationEnvironment + private fun getOrCreateApplicationEnvironmentForProduction(configuration: CompilerConfiguration, configFilePaths: List): JavaCoreApplicationEnvironment { synchronized (APPLICATION_LOCK) { if (ourApplicationEnvironment != null) 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 2e8e64aa1bf..8a572e2c261 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 @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.rmi.service import org.jetbrains.kotlin.cli.common.CLICompiler import org.jetbrains.kotlin.cli.common.ExitCode +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents import org.jetbrains.kotlin.progress.CompilationCanceledStatus @@ -166,7 +167,8 @@ class CompileServiceImpl( override fun releaseCompileSession(sessionId: Int) = ifAlive_Nothing(minAliveness = Aliveness.LastSession) { synchronized(state.sessions) { state.sessions.remove(sessionId) - // TODO: some cleanup goes here + log.info("cleaning after session") + clearJarCache() if (state.sessions.isEmpty()) { // TODO: and some goes here } @@ -473,6 +475,43 @@ class CompileServiceImpl( } } + private fun clearJarCache() { + callVoidStaticMethod("com.intellij.openapi.vfs.impl.ZipHandler", "clearFileAccessorCache") + val classloader = javaClass.classLoader + // TODO: replace the following code with direct call to CoreJarFileSystem. as soon as it will be available (hopefully in 15.02) + try { + KotlinCoreEnvironment.applicationEnvironment?.jarFileSystem.let { jarfs -> + val jarfsClass = classloader.loadClass("com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem") + val privateHandlersField = jarfsClass.getDeclaredField("myHandlers") + privateHandlersField.isAccessible = true + privateHandlersField.get(jarfs)?.let { + val clearMethod = privateHandlersField.type.getMethod("clear") + if (clearMethod != null) { + clearMethod.invoke(it) + log.info("successfully cleared com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem.myHandlers") + } + else { + log.info("unable to access com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem.myHandlers.clear") + } + } ?: log.info("unable to access CoreJarFileSystem.myHandlers (${privateHandlersField.get(jarfs)})") + } + } + catch (e: Exception) { + log.log(Level.SEVERE, "error clearing CoreJarFileSystem", e) + } + } + + // copied (with edit) from gradle plugin + private fun callVoidStaticMethod(classFqName: String, methodName: String) { + // compiler classloader == current classloader for now + // TODO: consider abstracting classloader, for easier changing it for a compiler + val cls = this.javaClass.classLoader.loadClass(classFqName) + + val method = cls.getMethod(methodName) + + method.invoke(null) + } + private fun ifAlive(minAliveness: Aliveness = Aliveness.Alive, ignoreCompilerChanged: Boolean = false, body: () -> R): CompileService.CallResult = rwlock.read { ifAliveChecksImpl(minAliveness, ignoreCompilerChanged) { CompileService.CallResult.Good(body()) } }