From 3afed7f972decec1d13b500c7a6f412014514bbe Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Tue, 20 Jul 2021 16:17:30 +0300 Subject: [PATCH] Fallback to CoreJarFileSystem when JDK doesn't support buffers unmapping --- .../cli/jvm/compiler/KotlinCoreEnvironment.kt | 24 ++++++++++++++++--- .../jvm/compiler/jarfs/FastJarFileSystem.kt | 23 ++++++++++-------- .../cli/jvm/compiler/jarfs/FastJarHandler.kt | 8 +++---- 3 files changed, 37 insertions(+), 18 deletions(-) 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 d0548aeeaa3..397d7609b40 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 @@ -69,7 +69,6 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.toBooleanLenient import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarFileSystem -import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarHandler import org.jetbrains.kotlin.cli.jvm.config.* import org.jetbrains.kotlin.cli.jvm.index.* import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar @@ -171,9 +170,28 @@ class KotlinCoreEnvironment private constructor( val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) + if (configuration.getBoolean(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM)) { + messageCollector?.report( + STRONG_WARNING, + "Using new faster version of JAR FS: it should make your build faster, but the new implementation is experimental" + ) + } + jarFileSystem = when { - configuration.getBoolean(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM) || - configuration.getBoolean(CommonConfigurationKeys.USE_FIR) -> FastJarFileSystem() + configuration.getBoolean(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM) || configuration.getBoolean(CommonConfigurationKeys.USE_FIR) -> { + val fastJarFs = FastJarFileSystem.createIfUnmappingPossible() + + if (fastJarFs == null) { + messageCollector?.report( + 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 { + fastJarFs + } + } + else -> applicationEnvironment.jarFileSystem } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/FastJarFileSystem.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/FastJarFileSystem.kt index a295b5315bc..41d70965bfe 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/FastJarFileSystem.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/FastJarFileSystem.kt @@ -19,7 +19,7 @@ import java.nio.channels.FileChannel private typealias RandomAccessFileAndBuffer = Pair -class FastJarFileSystem : DeprecatedVirtualFileSystem() { +class FastJarFileSystem private constructor(internal val unmapBuffer: MappedByteBuffer.() -> Unit) : DeprecatedVirtualFileSystem() { private val myHandlers: MutableMap = ConcurrentFactoryMap.createMap { key: String -> FastJarHandler(this@FastJarFileSystem, key) } @@ -69,25 +69,27 @@ class FastJarFileSystem : DeprecatedVirtualFileSystem() { val pathInJar = path.substring(separator + 2) return Couple.of(localPath, pathInJar) } + + fun createIfUnmappingPossible(): FastJarFileSystem? { + val cleanerCallBack = prepareCleanerCallback() ?: return null + return FastJarFileSystem(cleanerCallBack) + } } } private val IS_PRIOR_9_JRE = System.getProperty("java.specification.version", "").startsWith("1.") -internal fun ByteBuffer.unmapBuffer() { - if (!isDirect) return - - try { +private fun prepareCleanerCallback(): ((ByteBuffer) -> Unit)? { + return try { if (IS_PRIOR_9_JRE) { - val cleaner = this::class.java.getMethod("cleaner") - + val cleaner = Class.forName("java.nio.DirectByteBuffer").getMethod("cleaner") cleaner.isAccessible = true val clean = Class.forName("sun.misc.Cleaner").getMethod("clean") clean.isAccessible = true - clean.invoke(cleaner.invoke(this)) + { buffer: ByteBuffer -> clean.invoke(cleaner.invoke(buffer)) } } else { val unsafeClass = try { Class.forName("sun.misc.Unsafe") @@ -103,10 +105,11 @@ internal fun ByteBuffer.unmapBuffer() { val theUnsafeField = unsafeClass.getDeclaredField("theUnsafe") theUnsafeField.isAccessible = true - val theUnsafe = theUnsafeField.get(null) + val theUnsafe = theUnsafeField.get(null); - clean.invoke(theUnsafe, this) + { buffer: ByteBuffer -> clean.invoke(theUnsafe, buffer) } } } catch (ex: Exception) { + null } } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/FastJarHandler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/FastJarHandler.kt index 4ddb16ea9e5..a0cdffa6e0f 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/FastJarHandler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/FastJarHandler.kt @@ -8,14 +8,10 @@ import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.impl.ZipHandler import com.intellij.util.containers.FactoryMap -import com.intellij.util.io.FileAccessorCache import com.intellij.util.text.ByteArrayCharSequence -import java.io.File import java.io.FileNotFoundException import java.io.IOException import java.io.RandomAccessFile -import java.nio.ByteBuffer -import java.nio.MappedByteBuffer import java.nio.channels.FileChannel class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandler(path) { @@ -31,7 +27,9 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandl ourEntryMap = mappedByteBuffer.parseCentralDirectory().associateBy { it.relativePath } cachedManifest = ourEntryMap[MANIFEST_PATH]?.let(mappedByteBuffer::contentsToByteArray) } finally { - mappedByteBuffer.unmapBuffer() + with(fileSystem) { + mappedByteBuffer.unmapBuffer() + } } }