Fallback to CoreJarFileSystem when JDK doesn't support buffers unmapping

This commit is contained in:
Denis.Zharkov
2021-07-20 16:17:30 +03:00
committed by TeamCityServer
parent c6525974d0
commit 3afed7f972
3 changed files with 37 additions and 18 deletions
@@ -69,7 +69,6 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.toBooleanLenient import org.jetbrains.kotlin.cli.common.toBooleanLenient
import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarFileSystem 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.config.*
import org.jetbrains.kotlin.cli.jvm.index.* import org.jetbrains.kotlin.cli.jvm.index.*
import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar
@@ -171,9 +170,28 @@ class KotlinCoreEnvironment private constructor(
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) 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 { jarFileSystem = when {
configuration.getBoolean(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM) || configuration.getBoolean(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM) || configuration.getBoolean(CommonConfigurationKeys.USE_FIR) -> {
configuration.getBoolean(CommonConfigurationKeys.USE_FIR) -> FastJarFileSystem() 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 else -> applicationEnvironment.jarFileSystem
} }
@@ -19,7 +19,7 @@ import java.nio.channels.FileChannel
private typealias RandomAccessFileAndBuffer = Pair<RandomAccessFile, MappedByteBuffer> private typealias RandomAccessFileAndBuffer = Pair<RandomAccessFile, MappedByteBuffer>
class FastJarFileSystem : DeprecatedVirtualFileSystem() { class FastJarFileSystem private constructor(internal val unmapBuffer: MappedByteBuffer.() -> Unit) : DeprecatedVirtualFileSystem() {
private val myHandlers: MutableMap<String, FastJarHandler> = private val myHandlers: MutableMap<String, FastJarHandler> =
ConcurrentFactoryMap.createMap { key: String -> FastJarHandler(this@FastJarFileSystem, key) } ConcurrentFactoryMap.createMap { key: String -> FastJarHandler(this@FastJarFileSystem, key) }
@@ -69,25 +69,27 @@ class FastJarFileSystem : DeprecatedVirtualFileSystem() {
val pathInJar = path.substring(separator + 2) val pathInJar = path.substring(separator + 2)
return Couple.of(localPath, pathInJar) 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.") private val IS_PRIOR_9_JRE = System.getProperty("java.specification.version", "").startsWith("1.")
internal fun ByteBuffer.unmapBuffer() { private fun prepareCleanerCallback(): ((ByteBuffer) -> Unit)? {
if (!isDirect) return return try {
try {
if (IS_PRIOR_9_JRE) { if (IS_PRIOR_9_JRE) {
val cleaner = this::class.java.getMethod("cleaner") val cleaner = Class.forName("java.nio.DirectByteBuffer").getMethod("cleaner")
cleaner.isAccessible = true cleaner.isAccessible = true
val clean = Class.forName("sun.misc.Cleaner").getMethod("clean") val clean = Class.forName("sun.misc.Cleaner").getMethod("clean")
clean.isAccessible = true clean.isAccessible = true
clean.invoke(cleaner.invoke(this)) { buffer: ByteBuffer -> clean.invoke(cleaner.invoke(buffer)) }
} else { } else {
val unsafeClass = try { val unsafeClass = try {
Class.forName("sun.misc.Unsafe") Class.forName("sun.misc.Unsafe")
@@ -103,10 +105,11 @@ internal fun ByteBuffer.unmapBuffer() {
val theUnsafeField = unsafeClass.getDeclaredField("theUnsafe") val theUnsafeField = unsafeClass.getDeclaredField("theUnsafe")
theUnsafeField.isAccessible = true 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) { } catch (ex: Exception) {
null
} }
} }
@@ -8,14 +8,10 @@ import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.impl.ZipHandler import com.intellij.openapi.vfs.impl.ZipHandler
import com.intellij.util.containers.FactoryMap import com.intellij.util.containers.FactoryMap
import com.intellij.util.io.FileAccessorCache
import com.intellij.util.text.ByteArrayCharSequence import com.intellij.util.text.ByteArrayCharSequence
import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.IOException import java.io.IOException
import java.io.RandomAccessFile import java.io.RandomAccessFile
import java.nio.ByteBuffer
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel import java.nio.channels.FileChannel
class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandler(path) { 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 } ourEntryMap = mappedByteBuffer.parseCentralDirectory().associateBy { it.relativePath }
cachedManifest = ourEntryMap[MANIFEST_PATH]?.let(mappedByteBuffer::contentsToByteArray) cachedManifest = ourEntryMap[MANIFEST_PATH]?.let(mappedByteBuffer::contentsToByteArray)
} finally { } finally {
mappedByteBuffer.unmapBuffer() with(fileSystem) {
mappedByteBuffer.unmapBuffer()
}
} }
} }