[JS IR] Use cacheable ZIP file system accessor in JS IR BE

Related to KT-51712
This commit is contained in:
Alexander Korepanov
2023-02-27 17:36:48 +01:00
committed by Space Team
parent 8f22d6d36e
commit 2cad26f4cc
9 changed files with 80 additions and 20 deletions
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.cli.js package org.jetbrains.kotlin.cli.js
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.backend.common.CompilationException import org.jetbrains.kotlin.backend.common.CompilationException
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
@@ -55,6 +56,8 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
import org.jetbrains.kotlin.js.config.* import org.jetbrains.kotlin.js.config.*
import org.jetbrains.kotlin.konan.file.ZipFileSystemAccessor
import org.jetbrains.kotlin.konan.file.ZipFileSystemCacheableAccessor
import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion import org.jetbrains.kotlin.library.metadata.KlibMetadataVersion
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -74,6 +77,16 @@ private val K2JSCompilerArguments.granularity: JsGenerationGranularity
else -> JsGenerationGranularity.WHOLE_PROGRAM else -> JsGenerationGranularity.WHOLE_PROGRAM
} }
private class DisposableZipFileSystemAccessor private constructor(
private val zipAccessor: ZipFileSystemCacheableAccessor
) : Disposable, ZipFileSystemAccessor by zipAccessor {
constructor(cacheLimit: Int) : this(ZipFileSystemCacheableAccessor(cacheLimit))
override fun dispose() {
zipAccessor.reset()
}
}
class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() { class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
override val defaultPerformanceManager: CommonCompilerPerformanceManager = override val defaultPerformanceManager: CommonCompilerPerformanceManager =
@@ -194,6 +207,10 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
configurationJs.put(JSConfigurationKeys.GENERATE_DTS, arguments.generateDts) configurationJs.put(JSConfigurationKeys.GENERATE_DTS, arguments.generateDts)
configurationJs.put(JSConfigurationKeys.GENERATE_INLINE_ANONYMOUS_FUNCTIONS, arguments.irGenerateInlineAnonymousFunctions) configurationJs.put(JSConfigurationKeys.GENERATE_INLINE_ANONYMOUS_FUNCTIONS, arguments.irGenerateInlineAnonymousFunctions)
val zipAccessor = DisposableZipFileSystemAccessor(64)
Disposer.register(rootDisposable, zipAccessor)
configurationJs.put(JSConfigurationKeys.ZIP_FILE_SYSTEM_ACCESSOR, zipAccessor)
if (!checkKotlinPackageUsage(environmentForJS.configuration, sourcesFiles)) return COMPILATION_ERROR if (!checkKotlinPackageUsage(environmentForJS.configuration, sourcesFiles)) return COMPILATION_ERROR
val outputDirPath = arguments.outputDir val outputDirPath = arguments.outputDir
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.konan.properties.propertyList import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS
import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.KotlinLibrary
@@ -87,7 +88,8 @@ class CacheUpdater(
// libraries in topological order: [stdlib, ..., main] // libraries in topological order: [stdlib, ..., main]
val libraryDependencies = stopwatch.measure("Resolving and loading klib dependencies") { val libraryDependencies = stopwatch.measure("Resolving and loading klib dependencies") {
val allResolvedDependencies = CommonJsKLibResolver.resolve(allModules, compilerConfiguration.resolverLogger) val zipAccessor = compilerConfiguration.get(JSConfigurationKeys.ZIP_FILE_SYSTEM_ACCESSOR)
val allResolvedDependencies = CommonJsKLibResolver.resolve(allModules, compilerConfiguration.resolverLogger, zipAccessor)
val libraries = allResolvedDependencies.getFullList(TopologicalLibraryOrder).let { resolvedLibraries -> val libraries = allResolvedDependencies.getFullList(TopologicalLibraryOrder).let { resolvedLibraries ->
val mainLibraryIndex = resolvedLibraries.indexOfLast { val mainLibraryIndex = resolvedLibraries.indexOfLast {
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.common package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.file.ZipFileSystemAccessor
import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.KotlinLibraryProperResolverWithAttributes import org.jetbrains.kotlin.library.KotlinLibraryProperResolverWithAttributes
import org.jetbrains.kotlin.library.UnresolvedLibrary import org.jetbrains.kotlin.library.UnresolvedLibrary
@@ -16,15 +17,21 @@ import org.jetbrains.kotlin.library.metadata.resolver.impl.libraryResolver
import org.jetbrains.kotlin.util.Logger import org.jetbrains.kotlin.util.Logger
object CommonJsKLibResolver { object CommonJsKLibResolver {
fun resolve(libraries: Collection<String>, logger: Logger): KotlinLibraryResolveResult = fun resolve(
libraries: Collection<String>,
logger: Logger,
zipAccessor: ZipFileSystemAccessor? = null
): KotlinLibraryResolveResult =
resolveWithoutDependencies( resolveWithoutDependencies(
libraries, libraries,
logger logger,
zipAccessor
).resolveWithDependencies() ).resolveWithDependencies()
fun resolveWithoutDependencies( fun resolveWithoutDependencies(
libraries: Collection<String>, libraries: Collection<String>,
logger: Logger logger: Logger,
zipAccessor: ZipFileSystemAccessor?
): KLibResolution { ): KLibResolution {
val unresolvedLibraries = libraries.map { UnresolvedLibrary(it, null) } val unresolvedLibraries = libraries.map { UnresolvedLibrary(it, null) }
val libraryAbsolutePaths = libraries.map { File(it).absolutePath } val libraryAbsolutePaths = libraries.map { File(it).absolutePath }
@@ -35,7 +42,8 @@ object CommonJsKLibResolver {
distributionKlib = null, distributionKlib = null,
localKotlinDir = null, localKotlinDir = null,
skipCurrentDir = false, skipCurrentDir = false,
logger = logger logger = logger,
zipAccessor = zipAccessor
).libraryResolver() ).libraryResolver()
return KLibResolution( return KLibResolution(
@@ -67,7 +75,8 @@ private class KLibResolverHelper(
distributionKlib: String?, distributionKlib: String?,
localKotlinDir: String?, localKotlinDir: String?,
skipCurrentDir: Boolean, skipCurrentDir: Boolean,
logger: Logger logger: Logger,
private val zipAccessor: ZipFileSystemAccessor?
) : KotlinLibraryProperResolverWithAttributes<KotlinLibrary>( ) : KotlinLibraryProperResolverWithAttributes<KotlinLibrary>(
repositories, repositories,
directLibs, directLibs,
@@ -78,5 +87,5 @@ private class KLibResolverHelper(
emptyList() emptyList()
) { ) {
// Stick with the default KotlinLibrary for now. // Stick with the default KotlinLibrary for now.
override fun libraryComponentBuilder(file: File, isDefault: Boolean) = createKotlinLibraryComponents(file, isDefault) override fun libraryComponentBuilder(file: File, isDefault: Boolean) = createKotlinLibraryComponents(file, isDefault, zipAccessor)
} }
@@ -47,6 +47,7 @@ import org.jetbrains.kotlin.js.analyze.AbstractTopDownAnalyzerFacadeForWeb
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.konan.file.ZipFileSystemAccessor
import org.jetbrains.kotlin.konan.properties.Properties import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.properties.propertyList import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.library.* import org.jetbrains.kotlin.library.*
@@ -472,7 +473,8 @@ class ModulesStructure(
val allDependenciesResolution = CommonJsKLibResolver.resolveWithoutDependencies( val allDependenciesResolution = CommonJsKLibResolver.resolveWithoutDependencies(
dependencies, dependencies,
compilerConfiguration.resolverLogger compilerConfiguration.resolverLogger,
compilerConfiguration.get(JSConfigurationKeys.ZIP_FILE_SYSTEM_ACCESSOR)
) )
val fullResolvedLibraries by lazy { val fullResolvedLibraries by lazy {
+1
View File
@@ -4,6 +4,7 @@ plugins {
} }
dependencies { dependencies {
implementation(project(":kotlin-util-io"))
api(project(":compiler:util")) api(project(":compiler:util"))
api(project(":compiler:frontend")) api(project(":compiler:frontend"))
api(project(":core:compiler.common.js")) api(project(":core:compiler.common.js"))
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.js.config; package org.jetbrains.kotlin.js.config;
import org.jetbrains.kotlin.konan.file.ZipFileSystemAccessor;
import org.jetbrains.kotlin.config.CompilerConfigurationKey; import org.jetbrains.kotlin.config.CompilerConfigurationKey;
import org.jetbrains.kotlin.incremental.js.IncrementalNextRoundChecker; import org.jetbrains.kotlin.incremental.js.IncrementalNextRoundChecker;
import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider; import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider;
@@ -120,4 +121,8 @@ public class JSConfigurationKeys {
public static final CompilerConfigurationKey<Boolean> WASM_GENERATE_WAT = public static final CompilerConfigurationKey<Boolean> WASM_GENERATE_WAT =
CompilerConfigurationKey.create("generate wat file"); CompilerConfigurationKey.create("generate wat file");
public static final CompilerConfigurationKey<ZipFileSystemAccessor> ZIP_FILE_SYSTEM_ACCESSOR =
CompilerConfigurationKey.create("zip file system accessor, used for klib reading");
} }
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.test.converters.ClassicJsBackendFacade import org.jetbrains.kotlin.js.test.converters.ClassicJsBackendFacade
import org.jetbrains.kotlin.js.test.utils.MODULE_EMULATION_FILE import org.jetbrains.kotlin.js.test.utils.MODULE_EMULATION_FILE
import org.jetbrains.kotlin.js.testOld.V8IrJsTestChecker import org.jetbrains.kotlin.js.testOld.V8IrJsTestChecker
import org.jetbrains.kotlin.konan.file.ZipFileSystemCacheableAccessor
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.serialization.js.ModuleKind
@@ -61,10 +62,17 @@ abstract class AbstractInvalidationTest(
private const val SOURCE_MAPPING_URL_PREFIX = "//# sourceMappingURL=" private const val SOURCE_MAPPING_URL_PREFIX = "//# sourceMappingURL="
} }
private val zipAccessor = ZipFileSystemCacheableAccessor(2)
override fun createEnvironment(): KotlinCoreEnvironment { override fun createEnvironment(): KotlinCoreEnvironment {
return KotlinCoreEnvironment.createForTests(TestDisposable(), CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES) return KotlinCoreEnvironment.createForTests(TestDisposable(), CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
} }
override fun tearDown() {
zipAccessor.reset()
super.tearDown()
}
private fun parseProjectInfo(testName: String, infoFile: File): ProjectInfo { private fun parseProjectInfo(testName: String, infoFile: File): ProjectInfo {
return ProjectInfoParser(infoFile).parse(testName) return ProjectInfoParser(infoFile).parse(testName)
} }
@@ -127,6 +135,9 @@ abstract class AbstractInvalidationTest(
} }
build() build()
} }
zipAccessor.reset()
copy.put(JSConfigurationKeys.ZIP_FILE_SYSTEM_ACCESSOR, zipAccessor)
return copy return copy
} }
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.testOld.V8IrJsTestChecker import org.jetbrains.kotlin.js.testOld.V8IrJsTestChecker
import org.jetbrains.kotlin.klib.KlibABITestUtils import org.jetbrains.kotlin.klib.KlibABITestUtils
import org.jetbrains.kotlin.klib.KlibABITestUtils.MAIN_MODULE_NAME import org.jetbrains.kotlin.klib.KlibABITestUtils.MAIN_MODULE_NAME
import org.jetbrains.kotlin.konan.file.ZipFileSystemCacheableAccessor
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.serialization.js.ModuleKind
@@ -54,6 +55,8 @@ abstract class AbstractJsKLibABITestCase : KtUsefulTestCase() {
private lateinit var buildDir: File private lateinit var buildDir: File
private lateinit var environment: KotlinCoreEnvironment private lateinit var environment: KotlinCoreEnvironment
private val zipAccessor = ZipFileSystemCacheableAccessor(2)
override fun setUp() { override fun setUp() {
super.setUp() super.setUp()
buildDir = createTempDirectory().toFile().also { it.mkdirs() } buildDir = createTempDirectory().toFile().also { it.mkdirs() }
@@ -66,10 +69,24 @@ abstract class AbstractJsKLibABITestCase : KtUsefulTestCase() {
} }
override fun tearDown() { override fun tearDown() {
zipAccessor.reset()
buildDir.deleteRecursively() buildDir.deleteRecursively()
super.tearDown() super.tearDown()
} }
private fun createConfig(moduleName: String): CompilerConfiguration {
val config = environment.configuration.copy()
config.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
config.put(JSConfigurationKeys.PARTIAL_LINKAGE, true)
config.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
config.put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, true)
zipAccessor.reset()
config.put(JSConfigurationKeys.ZIP_FILE_SYSTEM_ACCESSOR, zipAccessor)
return config
}
private inner class JsTestConfiguration(testPath: String) : KlibABITestUtils.TestConfiguration { private inner class JsTestConfiguration(testPath: String) : KlibABITestUtils.TestConfiguration {
override val testDir: File = File(testPath).absoluteFile override val testDir: File = File(testPath).absoluteFile
override val buildDir: File get() = this@AbstractJsKLibABITestCase.buildDir override val buildDir: File get() = this@AbstractJsKLibABITestCase.buildDir
@@ -82,6 +99,7 @@ abstract class AbstractJsKLibABITestCase : KtUsefulTestCase() {
this@AbstractJsKLibABITestCase.buildBinaryAndRun(mainModuleKlibFile, dependencies) this@AbstractJsKLibABITestCase.buildBinaryAndRun(mainModuleKlibFile, dependencies)
override fun onNonEmptyBuildDirectory(directory: File) { override fun onNonEmptyBuildDirectory(directory: File) {
zipAccessor.reset()
directory.listFiles()?.forEach(File::deleteRecursively) directory.listFiles()?.forEach(File::deleteRecursively)
} }
@@ -108,11 +126,9 @@ abstract class AbstractJsKLibABITestCase : KtUsefulTestCase() {
fun doTest(testPath: String) = KlibABITestUtils.runTest(JsTestConfiguration(testPath)) fun doTest(testPath: String) = KlibABITestUtils.runTest(JsTestConfiguration(testPath))
private fun buildKlib(moduleName: String, moduleSourceDir: File, dependencies: KlibABITestUtils.Dependencies, klibFile: File) { private fun buildKlib(moduleName: String, moduleSourceDir: File, dependencies: KlibABITestUtils.Dependencies, klibFile: File) {
val config = createConfig(moduleName)
val ktFiles = environment.createPsiFiles(moduleSourceDir) val ktFiles = environment.createPsiFiles(moduleSourceDir)
val config = environment.configuration.copy()
config.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
val sourceModule = prepareAnalyzedSourceModule( val sourceModule = prepareAnalyzedSourceModule(
environment.project, environment.project,
ktFiles, ktFiles,
@@ -156,12 +172,7 @@ abstract class AbstractJsKLibABITestCase : KtUsefulTestCase() {
} }
private fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: KlibABITestUtils.Dependencies) { private fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: KlibABITestUtils.Dependencies) {
val configuration = environment.configuration.copy() val configuration = createConfig(MAIN_MODULE_NAME)
configuration.put(JSConfigurationKeys.PARTIAL_LINKAGE, true)
configuration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
configuration.put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, true)
configuration.put(CommonConfigurationKeys.MODULE_NAME, MAIN_MODULE_NAME)
val compilationOutputs = if (useIncrementalCompiler) val compilationOutputs = if (useIncrementalCompiler)
buildBinaryWithIC(configuration, mainModuleKlibFile, allDependencies) buildBinaryWithIC(configuration, mainModuleKlibFile, allDependencies)
@@ -50,7 +50,9 @@ abstract class AbstractJsKlibBinaryCompatibilityTest : AbstractKlibBinaryCompati
return uniqueDependencies return uniqueDependencies
} }
private val TestModule.jsPath get() = File(workingDir, "${this.name}.js").absolutePath private val jsOutDir get() = workingDir.resolve("out")
private val TestModule.jsPath get() = File(jsOutDir, "${this.name}.js").absolutePath
private fun createFiles(files: List<TestFile>): List<String> = private fun createFiles(files: List<TestFile>): List<String> =
files.map { files.map {
@@ -83,7 +85,7 @@ abstract class AbstractJsKlibBinaryCompatibilityTest : AbstractKlibBinaryCompati
val args = K2JSCompilerArguments().apply { val args = K2JSCompilerArguments().apply {
freeArgs = createFiles(module.files) + runnerFunctionFile() freeArgs = createFiles(module.files) + runnerFunctionFile()
libraries = module.dependenciesToLibrariesArg(version = 2) libraries = module.dependenciesToLibrariesArg(version = 2)
outputDir = workingDir.normalize().absolutePath outputDir = jsOutDir.normalize().absolutePath
moduleName = module.name moduleName = module.name
irProduceJs = true irProduceJs = true
irOnly = true irOnly = true