diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt index c8189dc50f7..a66f5a1da88 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt @@ -6,109 +6,14 @@ package org.jetbrains.kotlin.idea.klib import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.components.BaseComponent -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.util.containers.ContainerUtil.createConcurrentWeakValueMap -import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion -import org.jetbrains.kotlin.library.* -import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf -import org.jetbrains.kotlin.library.metadata.parseModuleHeader -import org.jetbrains.kotlin.library.metadata.parsePackageFragment -import org.jetbrains.kotlin.metadata.ProtoBuf -import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion -import java.io.IOException -import java.util.* -class KlibLoadingMetadataCache : BaseComponent { +// BUNCH: 192 +class KlibLoadingMetadataCache : KlibLoadingMetadataCacheCompat() { companion object { @JvmStatic fun getInstance(): KlibLoadingMetadataCache = - ApplicationManager.getApplication().getComponent(KlibLoadingMetadataCache::class.java) + ApplicationManager.getApplication().getService(KlibLoadingMetadataCache::class.java) } - // Use special CacheKey class instead of VirtualFile for cache keys. Certain types of VirtualFiles (for example, obtained from JarFileSystem) - // do not compare path (url) and modification stamp in equals() method. - private data class CacheKey( - val url: String, - val modificationStamp: Long - ) { - constructor(virtualFile: VirtualFile) : this(virtualFile.url, virtualFile.modificationStamp) - } - - // ConcurrentWeakValueHashMap does not allow null values. - private class CacheValue(val value: T?) - - private val packageFragmentCache = createConcurrentWeakValueMap>() - private val moduleHeaderCache = createConcurrentWeakValueMap>() - private val libraryMetadataVersionCache = createConcurrentWeakValueMap>() - - fun getCachedPackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? { - check(packageFragmentFile.extension == KLIB_METADATA_FILE_EXTENSION) { - "Not a package metadata file: $packageFragmentFile" - } - - return packageFragmentCache.computeIfAbsent( - CacheKey(packageFragmentFile) - ) { - CacheValue(computePackageFragment(packageFragmentFile)) - }.value - } - - fun getCachedModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? { - check(moduleHeaderFile.name == KLIB_MODULE_METADATA_FILE_NAME) { - "Not a module header file: $moduleHeaderFile" - } - - return moduleHeaderCache.computeIfAbsent( - CacheKey(moduleHeaderFile) - ) { - CacheValue(computeModuleHeader(moduleHeaderFile)) - }.value - } - - private fun isMetadataCompatible(libraryRoot: VirtualFile): Boolean { - val manifestFile = libraryRoot.findChild(KLIB_MANIFEST_FILE_NAME) ?: return false - - val metadataVersion = libraryMetadataVersionCache.computeIfAbsent( - CacheKey(manifestFile) - ) { - CacheValue(computeLibraryMetadataVersion(manifestFile)) - }.value ?: return false - - return metadataVersion.isCompatible() - } - - private fun computePackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? { - if (!isMetadataCompatible(packageFragmentFile.parent.parent.parent)) - return null - - return try { - parsePackageFragment(packageFragmentFile.contentsToByteArray(false)) - } catch (_: IOException) { - null - } - } - - private fun computeModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? { - if (!isMetadataCompatible(moduleHeaderFile.parent.parent)) - return null - - return try { - parseModuleHeader(moduleHeaderFile.contentsToByteArray(false)) - } catch (_: IOException) { - null - } - } - - private fun computeLibraryMetadataVersion(manifestFile: VirtualFile): KlibMetadataVersion? = try { - val versioning = Properties().apply { manifestFile.inputStream.use { load(it) } }.readKonanLibraryVersioning() - versioning.metadataVersion?.let(BinaryVersion.Companion::parseVersionArray)?.let(::KlibMetadataVersion) - } catch (_: IOException) { - // ignore and cache null value - null - } catch (_: IllegalArgumentException) { - // ignore and cache null value - null - } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt.192 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt.192 new file mode 100644 index 00000000000..0945e02b35a --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCache.kt.192 @@ -0,0 +1,20 @@ +/* + * Copyright 2010-2020 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.idea.klib + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.BaseComponent + +// BUNCH: 192 +class KlibLoadingMetadataCache : KlibLoadingMetadataCacheCompat(), BaseComponent { + + companion object { + @JvmStatic + fun getInstance(): KlibLoadingMetadataCache = + ApplicationManager.getApplication().getComponent(KlibLoadingMetadataCache::class.java) + } + +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCacheCompat.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCacheCompat.kt new file mode 100644 index 00000000000..1c03fd10369 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/klib/KlibLoadingMetadataCacheCompat.kt @@ -0,0 +1,110 @@ +/* + * Copyright 2010-2020 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.idea.klib + +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.containers.ContainerUtil.createConcurrentWeakValueMap +import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion +import org.jetbrains.kotlin.library.KLIB_MANIFEST_FILE_NAME +import org.jetbrains.kotlin.library.KLIB_METADATA_FILE_EXTENSION +import org.jetbrains.kotlin.library.KLIB_MODULE_METADATA_FILE_NAME +import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf +import org.jetbrains.kotlin.library.metadata.parseModuleHeader +import org.jetbrains.kotlin.library.metadata.parsePackageFragment +import org.jetbrains.kotlin.library.readKonanLibraryVersioning +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion +import java.io.IOException +import java.util.* + +// BUNCH: 192 +abstract class KlibLoadingMetadataCacheCompat { + + // Use special CacheKey class instead of VirtualFile for cache keys. Certain types of VirtualFiles (for example, obtained from JarFileSystem) + // do not compare path (url) and modification stamp in equals() method. + private data class CacheKey( + val url: String, + val modificationStamp: Long + ) { + constructor(virtualFile: VirtualFile) : this(virtualFile.url, virtualFile.modificationStamp) + } + + // ConcurrentWeakValueHashMap does not allow null values. + private class CacheValue(val value: T?) + + private val packageFragmentCache = createConcurrentWeakValueMap>() + private val moduleHeaderCache = createConcurrentWeakValueMap>() + private val libraryMetadataVersionCache = createConcurrentWeakValueMap>() + + fun getCachedPackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? { + check(packageFragmentFile.extension == KLIB_METADATA_FILE_EXTENSION) { + "Not a package metadata file: $packageFragmentFile" + } + + return packageFragmentCache.computeIfAbsent( + CacheKey(packageFragmentFile) + ) { + CacheValue(computePackageFragment(packageFragmentFile)) + }.value + } + + fun getCachedModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? { + check(moduleHeaderFile.name == KLIB_MODULE_METADATA_FILE_NAME) { + "Not a module header file: $moduleHeaderFile" + } + + return moduleHeaderCache.computeIfAbsent( + CacheKey(moduleHeaderFile) + ) { + CacheValue(computeModuleHeader(moduleHeaderFile)) + }.value + } + + private fun isMetadataCompatible(libraryRoot: VirtualFile): Boolean { + val manifestFile = libraryRoot.findChild(KLIB_MANIFEST_FILE_NAME) ?: return false + + val metadataVersion = libraryMetadataVersionCache.computeIfAbsent( + CacheKey(manifestFile) + ) { + CacheValue(computeLibraryMetadataVersion(manifestFile)) + }.value ?: return false + + return metadataVersion.isCompatible() + } + + private fun computePackageFragment(packageFragmentFile: VirtualFile): ProtoBuf.PackageFragment? { + if (!isMetadataCompatible(packageFragmentFile.parent.parent.parent)) + return null + + return try { + parsePackageFragment(packageFragmentFile.contentsToByteArray(false)) + } catch (_: IOException) { + null + } + } + + private fun computeModuleHeader(moduleHeaderFile: VirtualFile): KlibMetadataProtoBuf.Header? { + if (!isMetadataCompatible(moduleHeaderFile.parent.parent)) + return null + + return try { + parseModuleHeader(moduleHeaderFile.contentsToByteArray(false)) + } catch (_: IOException) { + null + } + } + + private fun computeLibraryMetadataVersion(manifestFile: VirtualFile): KlibMetadataVersion? = try { + val versioning = Properties().apply { manifestFile.inputStream.use { load(it) } }.readKonanLibraryVersioning() + versioning.metadataVersion?.let(BinaryVersion.Companion::parseVersionArray)?.let(::KlibMetadataVersion) + } catch (_: IOException) { + // ignore and cache null value + null + } catch (_: IllegalArgumentException) { + // ignore and cache null value + null + } +} diff --git a/idea/resources/META-INF/native-common.xml b/idea/resources/META-INF/native-common.xml index b28b66c048a..d41de1a902b 100644 --- a/idea/resources/META-INF/native-common.xml +++ b/idea/resources/META-INF/native-common.xml @@ -1,10 +1,4 @@ - - - org.jetbrains.kotlin.idea.klib.KlibLoadingMetadataCache - - - diff --git a/idea/resources/META-INF/native.xml b/idea/resources/META-INF/native.xml index 2242c8a48ac..620ed18ed14 100644 --- a/idea/resources/META-INF/native.xml +++ b/idea/resources/META-INF/native.xml @@ -1,5 +1,7 @@ + + diff --git a/idea/resources/META-INF/native.xml.192 b/idea/resources/META-INF/native.xml.192 index 60fe74140b3..1d9ff78b569 100644 --- a/idea/resources/META-INF/native.xml.192 +++ b/idea/resources/META-INF/native.xml.192 @@ -1,4 +1,10 @@ + + + org.jetbrains.kotlin.idea.klib.KlibLoadingMetadataCache + + + org.jetbrains.kotlin.ide.konan.KotlinNativeABICompatibilityChecker