From bc75a2185223adbcaff1e91b1521e976ebffd667 Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Tue, 3 Aug 2021 18:23:11 +0300 Subject: [PATCH] Optimize Strings representation at FastJarHandler --- .../compiler/jarfs/ByteArrayCharSequence.kt | 40 +++++++++++++++++++ .../cli/jvm/compiler/jarfs/FastJarHandler.kt | 15 ++++--- .../jvm/compiler/jarfs/ZipImplementation.kt | 8 ++-- 3 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/ByteArrayCharSequence.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/ByteArrayCharSequence.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/ByteArrayCharSequence.kt new file mode 100644 index 00000000000..fdbcbc752df --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/ByteArrayCharSequence.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package org.jetbrains.kotlin.cli.jvm.compiler.jarfs + +class ByteArrayCharSequence( + private val bytes: ByteArray, + private val start: Int = 0, + private val end: Int = bytes.size +) : CharSequence { + + override fun hashCode(): Int { + error("Do not try computing hashCode ByteArrayCharSequence") + } + + override fun equals(other: Any?): Boolean { + error("Do not try comparing ByteArrayCharSequence") + } + + override val length get() = end - start + + override fun get(index: Int): Char = bytes[index + start].toChar() + + override fun subSequence(startIndex: Int, endIndex: Int): CharSequence { + if (startIndex == 0 && endIndex == length) return this + return ByteArrayCharSequence(bytes, start + startIndex, start + endIndex) + } + + override fun toString(): String { + val chars = CharArray(length) + + for (i in 0 until length) { + chars[i] = bytes[i + start].toChar() + } + + return String(chars) + } +} + 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 81ec15d4bdb..27890ec64d8 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 @@ -4,6 +4,7 @@ */ package org.jetbrains.kotlin.cli.jvm.compiler.jarfs +import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.VirtualFile import java.io.File import java.io.FileNotFoundException @@ -22,7 +23,9 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) { val mappedByteBuffer = randomAccessFile.channel.map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length()) try { entries = mappedByteBuffer.parseCentralDirectory() - cachedManifest = entries.singleOrNull { it.relativePath == MANIFEST_PATH }?.let(mappedByteBuffer::contentsToByteArray) + cachedManifest = + entries.singleOrNull { StringUtil.equals(MANIFEST_PATH, it.relativePath) } + ?.let(mappedByteBuffer::contentsToByteArray) } finally { with(fileSystem) { mappedByteBuffer.unmapBuffer() @@ -66,8 +69,8 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) { ) } - private fun getOrCreateDirectory(entryName: String, directories: MutableMap): FastJarVirtualFile { - return directories.getOrPut(entryName) { + private fun getOrCreateDirectory(entryName: CharSequence, directories: MutableMap): FastJarVirtualFile { + return directories.getOrPut(entryName.toString()) { val (parentPath, shortName) = entryName.splitPath() val parentFile = getOrCreateDirectory(parentPath, directories) @@ -75,7 +78,7 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) { } } - private fun String.splitPath(): Pair { + private fun CharSequence.splitPath(): Pair { var slashIndex = this.length - 1 while (slashIndex >= 0 && this[slashIndex] != '/') { @@ -83,7 +86,7 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) { } if (slashIndex == -1) return Pair("", this) - return Pair(substring(0, slashIndex), substring(slashIndex + 1)) + return Pair(subSequence(0, slashIndex), subSequence(slashIndex + 1, this.length)) } fun findFileByPath(pathInJar: String): VirtualFile? { @@ -92,7 +95,7 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) { fun contentsToByteArray(zipEntryDescription: ZipEntryDescription): ByteArray { val relativePath = zipEntryDescription.relativePath - if (relativePath == MANIFEST_PATH) return cachedManifest ?: throw FileNotFoundException("$file!/$relativePath") + if (StringUtil.equals(relativePath, MANIFEST_PATH)) return cachedManifest ?: throw FileNotFoundException("$file!/$relativePath") return fileSystem.cachedOpenFileHandles[file].use { synchronized(it) { it.get().second.contentsToByteArray(zipEntryDescription) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/ZipImplementation.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/ZipImplementation.kt index decfb652d5d..32b296c9f3d 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/ZipImplementation.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/jarfs/ZipImplementation.kt @@ -12,12 +12,12 @@ import java.util.zip.Inflater class ZipEntryDescription( - val relativePath: String, + val relativePath: CharSequence, val compressedSize: Int, val uncompressedSize: Int, val offsetInFile: Int, val compressionKind: CompressionKind, - val fileNameSize: Int + val fileNameSize: Int, ) { enum class CompressionKind { @@ -101,7 +101,7 @@ fun MappedByteBuffer.parseCentralDirectory(): List { val name = if (bytesForName.all { it >= 0 }) - String(bytesForName.asASCICharArray()) + ByteArrayCharSequence(bytesForName) else String(bytesForName, Charsets.UTF_8) @@ -126,6 +126,4 @@ fun MappedByteBuffer.parseCentralDirectory(): List { return result } -private fun ByteArray.asASCICharArray(): CharArray = CharArray(size) { this@asASCICharArray[it].toChar() } - private fun ByteBuffer.getUnsignedShort(offset: Int): Int = java.lang.Short.toUnsignedInt(getShort(offset))