From 59173baf5a0b09cb756c827596ccefeff853d385 Mon Sep 17 00:00:00 2001 From: Alexander Korepanov Date: Thu, 13 Jan 2022 20:59:21 +0300 Subject: [PATCH] [JS IR] Pass forward -Xir-property-lazy-initialization option Pass forward -Xir-property-lazy-initialization option for the incremental cache. ^KT-50175 Fixed --- .../jetbrains/kotlin/cli/js/K2JsIrCompiler.kt | 2 +- .../ir/backend/js/JsIrBackendContext.kt | 3 +- .../kotlin/ir/backend/js/compiler.kt | 4 - .../kotlin/ir/backend/js/compilerWithIC.kt | 2 - .../kotlin/ir/backend/js/ic/fileUtil.kt | 9 +- .../kotlin/ir/backend/js/ic/invalidation.kt | 84 +++++++++++++------ .../kotlin/ir/backend/js/ic/CacheAccessors.kt | 7 +- .../services/CompilerConfigurationProvider.kt | 5 ++ .../kotlin/js/config/JSConfigurationKeys.java | 3 + .../js/test/AbstractJsKLibABITestCase.kt | 2 +- .../js/test/converters/JsIrBackendFacade.kt | 2 +- .../test/utils/JsIrIncrementalDataProvider.kt | 2 +- .../kotlin/gradle/Kotlin2JsGradlePluginIT.kt | 45 ++++++++++ .../kotlin2JsIrICProject/build.gradle.kts | 19 +++++ .../kotlin2JsIrICProject/gradle.properties | 3 + .../src/main/kotlin/Main.kt | 5 ++ .../src/main/kotlin/TopLevel.kt | 2 + 17 files changed, 156 insertions(+), 43 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/build.gradle.kts create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/gradle.properties create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/src/main/kotlin/Main.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/src/main/kotlin/TopLevel.kt diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt index 6d780746d30..f449d7ae550 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt @@ -153,6 +153,7 @@ class K2JsIrCompiler : CLICompiler() { val sourcesFiles = environmentForJS.getSourceFiles() configurationJs.put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage) + configurationJs.put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, arguments.irPropertyLazyInitialization) if (!checkKotlinPackageUsage(environmentForJS.configuration, sourcesFiles)) return ExitCode.COMPILATION_ERROR @@ -388,7 +389,6 @@ class K2JsIrCompiler : CLICompiler() { arguments.irDceRuntimeDiagnostic, messageCollector ), - propertyLazyInitialization = arguments.irPropertyLazyInitialization, baseClassIntoMetadata = arguments.irBaseClassInMetadata, safeExternalBoolean = arguments.irSafeExternalBoolean, safeExternalBooleanDiagnostic = RuntimeDiagnostic.resolve( diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index f496b01d008..d9a811ecc41 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -56,7 +56,6 @@ class JsIrBackendContext( override val scriptMode: Boolean = false, override val es6mode: Boolean = false, val dceRuntimeDiagnostic: RuntimeDiagnostic? = null, - propertyLazyInitialization: Boolean = false, val baseClassIntoMetadata: Boolean = false, val safeExternalBoolean: Boolean = false, val safeExternalBooleanDiagnostic: RuntimeDiagnostic? = null, @@ -141,7 +140,7 @@ class JsIrBackendContext( override val reflectionSymbols: ReflectionSymbols get() = intrinsics.reflectionSymbols override val propertyLazyInitialization: PropertyLazyInitialization = PropertyLazyInitialization( - enabled = propertyLazyInitialization, + enabled = configuration.getBoolean(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION), eagerInitialization = symbolTable.referenceClass(getJsInternalClass("EagerInitialization")) ) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index d08048660b1..0dfc546b361 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -51,7 +51,6 @@ fun compile( exportedDeclarations: Set = emptySet(), dceRuntimeDiagnostic: RuntimeDiagnostic? = null, es6mode: Boolean = false, - propertyLazyInitialization: Boolean, verifySignatures: Boolean = true, baseClassIntoMetadata: Boolean = false, safeExternalBoolean: Boolean = false, @@ -76,7 +75,6 @@ fun compile( exportedDeclarations, dceRuntimeDiagnostic, es6mode, - propertyLazyInitialization, baseClassIntoMetadata, safeExternalBoolean, safeExternalBooleanDiagnostic, @@ -97,7 +95,6 @@ fun compileIr( exportedDeclarations: Set, dceRuntimeDiagnostic: RuntimeDiagnostic?, es6mode: Boolean, - propertyLazyInitialization: Boolean, baseClassIntoMetadata: Boolean, safeExternalBoolean: Boolean, safeExternalBooleanDiagnostic: RuntimeDiagnostic?, @@ -123,7 +120,6 @@ fun compileIr( configuration, es6mode = es6mode, dceRuntimeDiagnostic = dceRuntimeDiagnostic, - propertyLazyInitialization = propertyLazyInitialization, baseClassIntoMetadata = baseClassIntoMetadata, safeExternalBoolean = safeExternalBoolean, safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt index c3a2968f415..df0bd3443b4 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt @@ -42,7 +42,6 @@ fun compileWithIC( es6mode: Boolean = false, multiModule: Boolean = false, relativeRequirePath: Boolean = false, - propertyLazyInitialization: Boolean = false, verifySignatures: Boolean = true, baseClassIntoMetadata: Boolean = false, lowerPerModule: Boolean = false, @@ -67,7 +66,6 @@ fun compileWithIC( configuration, es6mode = es6mode, dceRuntimeDiagnostic = dceRuntimeDiagnostic, - propertyLazyInitialization = propertyLazyInitialization, baseClassIntoMetadata = baseClassIntoMetadata, safeExternalBoolean = safeExternalBoolean, safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/fileUtil.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/fileUtil.kt index 7b00286fa64..52515bddd35 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/fileUtil.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/fileUtil.kt @@ -9,12 +9,13 @@ import java.io.File import java.io.PrintWriter // TODO md5 hash -data class CacheInfo(val path: String, val libPath: String, var flatHash: ULong, var transHash: ULong) { +data class CacheInfo(val path: String, val libPath: String, var flatHash: ULong, var transHash: ULong, var configHash: ULong) { fun save() { PrintWriter(File(File(path), "info")).use { it.println(libPath) it.println(flatHash.toString(16)) it.println(transHash.toString(16)) + it.println(configHash.toString(16)) } } @@ -24,9 +25,11 @@ data class CacheInfo(val path: String, val libPath: String, var flatHash: ULong, if (!info.exists()) return null - val (libPath, flatHash, transHash) = info.readLines() + val (libPath, flatHash, transHash, configHash) = info.readLines() - return CacheInfo(path, libPath, flatHash.toULong(16), transHash.toULong(16)) + // safe cast for the backward compatibility with the cache from the previous compiler versions + val configHashULong = configHash.toULongOrNull(16) ?: 0UL + return CacheInfo(path, libPath, flatHash.toULong(16), transHash.toULong(16), configHashULong) } } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/invalidation.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/invalidation.kt index f7342038cb5..cd48645d79f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/invalidation.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/invalidation.kt @@ -51,7 +51,8 @@ private fun invalidateCacheForModule( cacheProvider: PersistentCacheProvider, cacheConsumer: PersistentCacheConsumer, signatureResolver: (String, Int) -> IdSignature, - fileFingerPrints: MutableMap + fileFingerPrints: MutableMap, + configUpdated: Boolean ): Pair, Collection> { val dirtyFiles = mutableSetOf() @@ -64,7 +65,7 @@ private fun invalidateCacheForModule( // 2. calculate new fingerprints val fileNewFingerprint = library.fingerprint(index) - if (fileOldFingerprint != fileNewFingerprint) { + if (fileOldFingerprint != fileNewFingerprint || configUpdated) { fileFingerPrints[file] = fileNewFingerprint cachedInlineHashesForFile.remove(file) @@ -203,9 +204,25 @@ private fun buildCacheForModule( // TODO: actual way of building a cache could change in future - cacheExecutor.execute(irModule, dependencies, deserializer, configuration, dirtyFiles, deletedFiles, cacheConsumer, emptySet(), mainArguments) + cacheExecutor.execute( + irModule, + dependencies, + deserializer, + configuration, + dirtyFiles, + deletedFiles, + cacheConsumer, + emptySet(), + mainArguments + ) - cacheConsumer.commitLibraryInfo(libraryInfo.libPath.toCanonicalPath(), libraryInfo.flatHash, libraryInfo.transHash, irModule.name.asString()) + cacheConsumer.commitLibraryInfo( + libraryInfo.libPath.toCanonicalPath(), + libraryInfo.flatHash, + libraryInfo.transHash, + libraryInfo.configHash, + irModule.name.asString() + ) } private fun loadModules( @@ -315,24 +332,11 @@ fun interface CacheExecutor { ) } -private fun File.md5(): ULong { +private fun calcMD5(feeder: (MessageDigest) -> Unit): ULong { val md5 = MessageDigest.getInstance("MD5") - - fun File.process(prefix: String = "") { - if (isDirectory) { - this.listFiles()!!.sortedBy { it.name }.forEach { - md5.update((prefix + it.name).toByteArray()) - it.process(prefix + it.name + "/") - } - } else { - md5.update(readBytes()) - } - } - - this.process() + feeder(md5) val d = md5.digest() - return ((d[0].toULong() and 0xFFUL) or ((d[1].toULong() and 0xFFUL) shl 8) or ((d[2].toULong() and 0xFFUL) shl 16) @@ -344,6 +348,30 @@ private fun File.md5(): ULong { ) } +private fun File.md5(): ULong { + fun File.process(md5: MessageDigest, prefix: String = "") { + if (isDirectory) { + this.listFiles()!!.sortedBy { it.name }.forEach { + md5.update((prefix + it.name).toByteArray()) + it.process(md5, prefix + it.name + "/") + } + } else { + md5.update(readBytes()) + } + } + return calcMD5 { this.process(it) } +} + +private fun CompilerConfiguration.calcMD5(): ULong { + val importantBooleanSettingKeys = listOf(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION) + return calcMD5 { + for (key in importantBooleanSettingKeys) { + it.update(key.toString().toByteArray()) + it.update(getBoolean(key).toString().toByteArray()) + } + } +} + private fun checkLibrariesHash( libraries: Map, dependencyGraph: Map>, @@ -391,8 +419,9 @@ fun actualizeCacheForModule( mainArguments: List?, executor: CacheExecutor ): CacheUpdateStatus { + val configMD5 = compilerConfiguration.calcMD5() val modulePath = moduleName.toCanonicalPath() - val cacheInfo = CacheInfo.load(cachePath) ?: CacheInfo(cachePath, modulePath, 0UL, 0UL) + val cacheInfo = CacheInfo.load(cachePath) ?: CacheInfo(cachePath, modulePath, 0UL, 0UL, configMD5) val icCacheMap: Map = loadCacheInfo(icCachePaths).also { it[modulePath] = cacheInfo } @@ -405,7 +434,9 @@ fun actualizeCacheForModule( } } - if (checkLibrariesHash(libraries, dependencyGraph, icCacheMap, modulePath)) { + val configUpdated = configMD5 != cacheInfo.configHash + cacheInfo.configHash = configMD5 + if (checkLibrariesHash(libraries, dependencyGraph, icCacheMap, modulePath) && !configUpdated) { return CacheUpdateStatus.FAST_PATH // up-to-date } @@ -425,7 +456,8 @@ fun actualizeCacheForModule( persistentCacheConsumer, irFactory, mainArguments, - executor + executor, + configUpdated ) } @@ -439,7 +471,8 @@ private fun actualizeCacheForModule( persistentCacheConsumer: PersistentCacheConsumer, irFactory: IrFactory, mainArguments: List?, - cacheExecutor: CacheExecutor + cacheExecutor: CacheExecutor, + configUpdated: Boolean ): CacheUpdateStatus { // 1. Invalidate val dependencies = dependencyGraph[library]!! @@ -486,7 +519,8 @@ private fun actualizeCacheForModule( currentLibraryCacheProvider, persistentCacheConsumer, signatureResolver, - fileFingerPrints + fileFingerPrints, + configUpdated ) if (dirtySet.isEmpty()) return CacheUpdateStatus.NO_DIRTY_FILES // up-to-date @@ -582,7 +616,7 @@ fun rebuildCacheForDirtyFiles( val currentIrModule = irModules.find { it.second == library }?.first!! - cacheConsumer.commitLibraryInfo(library.libraryFile.path.toCanonicalPath(), 0UL, 0UL, currentIrModule.name.asString()) + cacheConsumer.commitLibraryInfo(library.libraryFile.path.toCanonicalPath(), 0UL, 0UL, 0UL, currentIrModule.name.asString()) buildCacheForModuleFiles( currentIrModule, diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheAccessors.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheAccessors.kt index 9aac53944e4..43a144df69c 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheAccessors.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheAccessors.kt @@ -203,7 +203,7 @@ interface PersistentCacheConsumer { fun commitSourceMap(path: String, mapData: ByteArray) fun invalidateForFile(path: String) - fun commitLibraryInfo(libraryPath: String, flatHash: ULong, transHash: ULong, moduleName: String) + fun commitLibraryInfo(libraryPath: String, flatHash: ULong, transHash: ULong, configHash: ULong, moduleName: String) companion object { val EMPTY = object : PersistentCacheConsumer { @@ -231,7 +231,7 @@ interface PersistentCacheConsumer { } - override fun commitLibraryInfo(libraryPath: String, flatHash: ULong, transHash: ULong, moduleName: String) { + override fun commitLibraryInfo(libraryPath: String, flatHash: ULong, transHash: ULong, configHash: ULong, moduleName: String) { } @@ -324,7 +324,7 @@ class PersistentCacheConsumerImpl(private val cachePath: String) : PersistentCac commitByteArrayToCacheFile(path, fileSourceMap, mapData) } - override fun commitLibraryInfo(libraryPath: String, flatHash: ULong, transHash: ULong, moduleName: String) { + override fun commitLibraryInfo(libraryPath: String, flatHash: ULong, transHash: ULong, configHash: ULong, moduleName: String) { val infoFile = File(File(cachePath), "info") if (infoFile.exists()) { infoFile.delete() @@ -335,6 +335,7 @@ class PersistentCacheConsumerImpl(private val cachePath: String) : PersistentCac it.println(libraryPath) it.println(flatHash.toString(16)) it.println(transHash.toString(16)) + it.println(configHash.toString(16)) it.println(moduleName) } } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt index 110029fa040..f24a46e7ace 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfigurationKey import org.jetbrains.kotlin.config.languageVersionSettings +import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.platform.js.isJs import org.jetbrains.kotlin.platform.jvm.isJvm @@ -26,6 +27,7 @@ import org.jetbrains.kotlin.platform.konan.isNative import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.ApplicationEnvironmentDisposer import org.jetbrains.kotlin.test.TestInfrastructureInternals +import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives import org.jetbrains.kotlin.test.model.FrontendKinds import org.jetbrains.kotlin.test.model.TestFile import org.jetbrains.kotlin.test.model.TestModule @@ -98,6 +100,9 @@ open class CompilerConfigurationProviderImpl( fun createCompilerConfiguration(module: TestModule): CompilerConfiguration { val configuration = CompilerConfiguration() configuration[CommonConfigurationKeys.MODULE_NAME] = module.name + if (JsEnvironmentConfigurationDirectives.PROPERTY_LAZY_INITIALIZATION in module.directives) { + configuration.put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, true) + } if (module.frontendKind == FrontendKinds.FIR) { configuration[CommonConfigurationKeys.USE_FIR] = true diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/config/JSConfigurationKeys.java b/js/js.frontend/src/org/jetbrains/kotlin/js/config/JSConfigurationKeys.java index f3ca1418723..3877733db44 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/config/JSConfigurationKeys.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/config/JSConfigurationKeys.java @@ -96,4 +96,7 @@ public class JSConfigurationKeys { public static final CompilerConfigurationKey PARTIAL_LINKAGE = CompilerConfigurationKey.create("allows some symbols in klibs be missed"); + + public static final CompilerConfigurationKey PROPERTY_LAZY_INITIALIZATION = + CompilerConfigurationKey.create("perform lazy initialization for properties"); } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsKLibABITestCase.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsKLibABITestCase.kt index cef7e20d2f0..bbf6e1467fb 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsKLibABITestCase.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsKLibABITestCase.kt @@ -29,6 +29,7 @@ abstract class AbstractJsKLibABITestCase : AbstractKlibABITestCase() { override fun compileBinaryAndRun(project: Project, configuration: CompilerConfiguration, libraries: Collection, mainModulePath: String, buildDir: File) { 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 kLib = MainModule.Klib(mainModulePath) val moduleStructure = ModulesStructure(project, kLib, configuration, libraries, emptyList()) @@ -38,7 +39,6 @@ abstract class AbstractJsKLibABITestCase : AbstractKlibABITestCase() { PhaseConfig(jsPhases), IrFactoryImplForJsIC(WholeWorldStageController()), exportedDeclarations = setOf(FqName("box")), - propertyLazyInitialization = true, granularity = JsGenerationGranularity.PER_MODULE, icCompatibleIr2Js = true ) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt index 8163e92e832..bd197b229c1 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt @@ -58,6 +58,7 @@ class JsIrBackendFacade( override fun transform(module: TestModule, inputArtifact: BinaryArtifacts.KLib): BinaryArtifacts.Js? { val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module) + val isMainModule = JsEnvironmentConfigurator.isMainModule(module, testServices) if (!isMainModule) return null @@ -133,7 +134,6 @@ class JsIrBackendFacade( exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, TEST_FUNCTION))), dceRuntimeDiagnostic = null, es6mode = false, - propertyLazyInitialization = JsEnvironmentConfigurationDirectives.PROPERTY_LAZY_INITIALIZATION in module.directives, baseClassIntoMetadata = false, safeExternalBoolean = JsEnvironmentConfigurationDirectives.SAFE_EXTERNAL_BOOLEAN in module.directives, safeExternalBooleanDiagnostic = module.directives[JsEnvironmentConfigurationDirectives.SAFE_EXTERNAL_BOOLEAN_DIAGNOSTIC].singleOrNull(), diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/JsIrIncrementalDataProvider.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/JsIrIncrementalDataProvider.kt index b43e0e1d53a..e7f3aaba2ac 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/JsIrIncrementalDataProvider.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/JsIrIncrementalDataProvider.kt @@ -112,7 +112,7 @@ class TestModuleCache(val files: MutableMap) { files.remove(path) } - override fun commitLibraryInfo(libraryPath: String, flatHash: ULong, transHash: ULong, moduleName: String) { + override fun commitLibraryInfo(libraryPath: String, flatHash: ULong, transHash: ULong, configHash: ULong, moduleName: String) { storedModuleName = moduleName } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt index 9da025cf658..1b0b7b149b3 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt @@ -124,6 +124,51 @@ class Kotlin2JsIrGradlePluginIT : AbstractKotlin2JsGradlePluginIT(true) { build("assemble") } } + + @DisplayName("Check IR incremental cache invalidation by compiler args") + @GradleTest + fun testJsIrIncrementalCacheInvalidationByArgs(gradleVersion: GradleVersion) { + project("kotlin2JsIrICProject", gradleVersion) { + val buildConfig = buildGradleKts.readText() + + fun setLazyInitializationArg(value: Boolean) { + buildGradleKts.writeText(buildConfig) + buildGradleKts.appendText( + """ + | + |tasks.named("compileDevelopmentExecutableKotlinJs") { + | kotlinOptions { + | freeCompilerArgs += "-Xir-property-lazy-initialization=$value" + | } + |} + """.trimMargin() + ) + } + + fun String.testScriptOutLines() = this.lines().mapNotNull { + val trimmed = it.removePrefix(">>> TEST OUT: ") + if (trimmed == it) null else trimmed + } + + // -Xir-property-lazy-initialization default is true + build("nodeRun") { + assertTasksExecuted(":compileDevelopmentExecutableKotlinJs") + assertEquals(listOf("Hello, Gradle."), output.testScriptOutLines()) + } + + setLazyInitializationArg(false) + build("nodeRun") { + assertTasksExecuted(":compileDevelopmentExecutableKotlinJs") + assertEquals(listOf("TOP LEVEL!", "Hello, Gradle."), output.testScriptOutLines()) + } + + setLazyInitializationArg(true) + build("nodeRun") { + assertTasksExecuted(":compileDevelopmentExecutableKotlinJs") + assertEquals(listOf("Hello, Gradle."), output.testScriptOutLines()) + } + } + } } @JsGradlePluginTests diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/build.gradle.kts new file mode 100644 index 00000000000..bc033346ded --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + kotlin("js") +} + +group = "com.example" +version = "1.0" + + +repositories { + mavenCentral() + mavenLocal() +} + +kotlin { + js(IR) { + binaries.executable() + nodejs {} + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/gradle.properties new file mode 100644 index 00000000000..1ad40858996 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/gradle.properties @@ -0,0 +1,3 @@ +kotlin.code.style=official +kotlin.incremental.js.ir=true +kotlin.incremental.js.klib=true diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/src/main/kotlin/Main.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/src/main/kotlin/Main.kt new file mode 100644 index 00000000000..42b5f2819b7 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/src/main/kotlin/Main.kt @@ -0,0 +1,5 @@ +fun main() { + println(greeting("Gradle")) +} + +fun greeting(name: String) = ">>> TEST OUT: Hello, $name." diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/src/main/kotlin/TopLevel.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/src/main/kotlin/TopLevel.kt new file mode 100644 index 00000000000..35954e4d189 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsIrICProject/src/main/kotlin/TopLevel.kt @@ -0,0 +1,2 @@ +@JsExport +val topLevelForLazy = { println(">>> TEST OUT: TOP LEVEL!"); 0 }()