Preserve FastJarFS in app env and implement intermediate cleanup
FastJarFS was behaving differently than the regular CoreJarFS it tries to replace, namely it was cleaned after each compilation (had the lifetime tied to core env). This commit preserve it in the app env the same way as CoreJarFS, so it could be reused in parallel builds and preserved if automatic cleanup of the app env is turned off, But since FastJarFS caches also mmf handles, the additional handles cleaning is introduced that triggers after all possibly parallel compilations are finished.
This commit is contained in:
committed by
Space Team
parent
61e9aaf113
commit
7d5257c258
+35
-3
@@ -11,27 +11,59 @@ import com.intellij.core.JavaCoreApplicationEnvironment
|
||||
import com.intellij.lang.MetaLanguage
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vfs.VirtualFileSystem
|
||||
import com.intellij.psi.FileContextProvider
|
||||
import com.intellij.psi.augment.PsiAugmentProvider
|
||||
import com.intellij.psi.impl.smartPointers.SmartPointerAnchorProvider
|
||||
import com.intellij.psi.meta.MetaDataContributor
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.IdeaExtensionPoints.registerVersionSpecificAppExtensionPoints
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarFileSystem
|
||||
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
|
||||
|
||||
class KotlinCoreApplicationEnvironment private constructor(parentDisposable: Disposable, unitTestMode: Boolean) :
|
||||
class KotlinCoreApplicationEnvironment private constructor(
|
||||
parentDisposable: Disposable, unitTestMode: Boolean
|
||||
) :
|
||||
JavaCoreApplicationEnvironment(parentDisposable, unitTestMode) {
|
||||
override fun createJrtFileSystem(): VirtualFileSystem? {
|
||||
|
||||
override fun createJrtFileSystem(): VirtualFileSystem {
|
||||
return CoreJrtFileSystem()
|
||||
}
|
||||
|
||||
private var fastJarFileSystemField: FastJarFileSystem? = null
|
||||
private var fastJarFileSystemFieldInitialized = false
|
||||
|
||||
val fastJarFileSystem: FastJarFileSystem?
|
||||
get() {
|
||||
synchronized(KotlinCoreEnvironment.APPLICATION_LOCK) {
|
||||
if (!fastJarFileSystemFieldInitialized) {
|
||||
|
||||
// may return null e.g. on the old JDKs, therefore fastJarFileSystemFieldInitialized flag is needed
|
||||
fastJarFileSystemField = FastJarFileSystem.createIfUnmappingPossible()?.also {
|
||||
Disposer.register(parentDisposable) {
|
||||
it.clearHandlersCache()
|
||||
}
|
||||
}
|
||||
fastJarFileSystemFieldInitialized = true
|
||||
}
|
||||
return fastJarFileSystemField
|
||||
}
|
||||
}
|
||||
|
||||
fun idleCleanup() {
|
||||
fastJarFileSystemField?.cleanOpenFilesCache()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(parentDisposable: Disposable, unitTestMode: Boolean): KotlinCoreApplicationEnvironment {
|
||||
fun create(
|
||||
parentDisposable: Disposable, unitTestMode: Boolean
|
||||
): KotlinCoreApplicationEnvironment {
|
||||
val environment = KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode)
|
||||
registerExtensionPoints()
|
||||
return environment
|
||||
}
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
private fun registerExtensionPoints() {
|
||||
registerApplicationExtensionPoint(DynamicBundle.LanguageBundleEP.EP_NAME, DynamicBundle.LanguageBundleEP::class.java)
|
||||
registerApplicationExtensionPoint(FileContextProvider.EP_NAME, FileContextProvider::class.java)
|
||||
|
||||
@@ -60,7 +60,6 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.toBooleanLenient
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarFileSystem
|
||||
import org.jetbrains.kotlin.cli.jvm.config.*
|
||||
import org.jetbrains.kotlin.cli.jvm.index.*
|
||||
import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar
|
||||
@@ -134,22 +133,14 @@ class KotlinCoreEnvironment private constructor(
|
||||
applicationEnvironment.jarFileSystem
|
||||
}
|
||||
configuration.getBoolean(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM) || configuration.getBoolean(CommonConfigurationKeys.USE_FIR) -> {
|
||||
val fastJarFs = FastJarFileSystem.createIfUnmappingPossible()
|
||||
|
||||
val fastJarFs = applicationEnvironment.fastJarFileSystem
|
||||
if (fastJarFs == null) {
|
||||
messageCollector?.report(
|
||||
STRONG_WARNING,
|
||||
CompilerMessageSeverity.STRONG_WARNING,
|
||||
"Your JDK doesn't seem to support mapped buffer unmapping, so the slower (old) version of JAR FS will be used"
|
||||
)
|
||||
applicationEnvironment.jarFileSystem
|
||||
} else {
|
||||
|
||||
Disposer.register(disposable) {
|
||||
fastJarFs.clearHandlersCache()
|
||||
}
|
||||
|
||||
fastJarFs
|
||||
}
|
||||
} else fastJarFs
|
||||
}
|
||||
|
||||
else -> applicationEnvironment.jarFileSystem
|
||||
@@ -464,7 +455,10 @@ class KotlinCoreEnvironment private constructor(
|
||||
): KotlinCoreEnvironment {
|
||||
val configuration = initialConfiguration.copy()
|
||||
// Tests are supposed to create a single project and dispose it right after use
|
||||
val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
|
||||
val appEnv =
|
||||
createApplicationEnvironment(
|
||||
parentDisposable, configuration, unitTestMode = true
|
||||
)
|
||||
val projectEnv = ProjectEnvironment(parentDisposable, appEnv, configuration)
|
||||
return KotlinCoreEnvironment(projectEnv, configuration, extensionConfigs)
|
||||
}
|
||||
@@ -479,7 +473,11 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
@TestOnly
|
||||
fun createProjectEnvironmentForTests(parentDisposable: Disposable, configuration: CompilerConfiguration): ProjectEnvironment {
|
||||
val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
|
||||
val appEnv = createApplicationEnvironment(
|
||||
parentDisposable,
|
||||
configuration,
|
||||
unitTestMode = true
|
||||
)
|
||||
return ProjectEnvironment(parentDisposable, appEnv, configuration)
|
||||
}
|
||||
|
||||
@@ -500,7 +498,12 @@ class KotlinCoreEnvironment private constructor(
|
||||
synchronized(APPLICATION_LOCK) {
|
||||
if (ourApplicationEnvironment == null) {
|
||||
val disposable = Disposer.newDisposable("Disposable for the KotlinCoreApplicationEnvironment")
|
||||
ourApplicationEnvironment = createApplicationEnvironment(disposable, configuration, unitTestMode)
|
||||
ourApplicationEnvironment =
|
||||
createApplicationEnvironment(
|
||||
disposable,
|
||||
configuration,
|
||||
unitTestMode
|
||||
)
|
||||
ourProjectCount = 0
|
||||
Disposer.register(disposable, Disposable {
|
||||
synchronized(APPLICATION_LOCK) {
|
||||
@@ -509,26 +512,28 @@ class KotlinCoreEnvironment private constructor(
|
||||
})
|
||||
}
|
||||
try {
|
||||
// Do not use this property unless you sure need it, causes Application to MEMORY LEAK
|
||||
// Only valid use-case is when Application should be cached to avoid
|
||||
// initialization costs
|
||||
if (CompilerSystemProperties.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY.value.toBooleanLenient() != true) {
|
||||
// Disposer uses identity of passed object to deduplicate registered disposables
|
||||
// We should everytime pass new instance to avoid un-registering from previous one
|
||||
@Suppress("ObjectLiteralToLambda")
|
||||
Disposer.register(parentDisposable, object : Disposable {
|
||||
override fun dispose() {
|
||||
synchronized(APPLICATION_LOCK) {
|
||||
// Build-systems may run many instances of the compiler in parallel
|
||||
// All projects share the same ApplicationEnvironment, and when the last project is disposed,
|
||||
// the ApplicationEnvironment is disposed as well
|
||||
if (--ourProjectCount <= 0) {
|
||||
// Disposer uses identity of passed object to deduplicate registered disposables
|
||||
// We should everytime pass new instance to avoid un-registering from previous one
|
||||
@Suppress("ObjectLiteralToLambda")
|
||||
Disposer.register(parentDisposable, object : Disposable {
|
||||
override fun dispose() {
|
||||
synchronized(APPLICATION_LOCK) {
|
||||
// Build-systems may run many instances of the compiler in parallel
|
||||
// All projects share the same ApplicationEnvironment, and when the last project is disposed,
|
||||
// the ApplicationEnvironment is disposed as well
|
||||
if (--ourProjectCount <= 0) {
|
||||
// Do not use this property unless you sure need it, causes Application to MEMORY LEAK
|
||||
// Only valid use-case is when Application should be cached to avoid
|
||||
// initialization costs
|
||||
if (CompilerSystemProperties.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY.value.toBooleanLenient() != true) {
|
||||
disposeApplicationEnvironment()
|
||||
} else {
|
||||
ourApplicationEnvironment?.idleCleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
} finally {
|
||||
ourProjectCount++
|
||||
}
|
||||
@@ -578,7 +583,9 @@ class KotlinCoreEnvironment private constructor(
|
||||
private fun createApplicationEnvironment(
|
||||
parentDisposable: Disposable, configuration: CompilerConfiguration, unitTestMode: Boolean
|
||||
): KotlinCoreApplicationEnvironment {
|
||||
val applicationEnvironment = KotlinCoreApplicationEnvironment.create(parentDisposable, unitTestMode)
|
||||
val applicationEnvironment = KotlinCoreApplicationEnvironment.create(
|
||||
parentDisposable, unitTestMode
|
||||
)
|
||||
|
||||
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/compiler.xml")
|
||||
|
||||
|
||||
@@ -58,6 +58,10 @@ class FastJarFileSystem private constructor(internal val unmapBuffer: MappedByte
|
||||
|
||||
fun clearHandlersCache() {
|
||||
myHandlers.clear()
|
||||
cleanOpenFilesCache()
|
||||
}
|
||||
|
||||
fun cleanOpenFilesCache() {
|
||||
cachedOpenFileHandles.clear()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user