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 26c323562d9..fd2c91f3534 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 @@ -5,10 +5,8 @@ package org.jetbrains.kotlin.ir.backend.js -import org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.PhaserState -import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.backend.js.ic.ModuleCache @@ -17,8 +15,8 @@ import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.* +import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName import org.jetbrains.kotlin.ir.backend.js.utils.serialization.JsIrAstDeserializer -import org.jetbrains.kotlin.ir.declarations.IrFactory import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.descriptors.IrBuiltInsOverDescriptors import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator @@ -107,6 +105,8 @@ fun compileWithIC( val ast = transformer.generateBinaryAst(dirtyFiles) ast.entries.forEach { (path, bytes) -> cacheConsumer.commitBinaryAst(path, bytes) } + + cacheConsumer.commitModuleName(module.name.asString()) } fun lowerPreservingTags(modules: Iterable, context: JsIrBackendContext, phaseConfig: PhaseConfig, controller: WholeWorldStageController) { @@ -131,15 +131,21 @@ fun generateJsFromAst( caches: Map, ): CompilerResult { val deserializer = JsIrAstDeserializer() - val fragments = JsIrProgram(caches.values.map { JsIrModule(it.name, it.name, it.asts.values.sortedBy { it.name }.mapNotNull { it.ast?.let { deserializer.deserialize(ByteArrayInputStream(it))} }) }) + val jsIrProgram = JsIrProgram(caches.values.map { + JsIrModule( + it.name.safeModuleName, + sanitizeName(it.name.safeModuleName), + it.asts.values.sortedBy { it.name }.mapNotNull { it.ast?.let { deserializer.deserialize(ByteArrayInputStream(it)) } }) + }) return CompilerResult( - generateSingleWrappedModuleBody( - mainModuleName, - moduleKind, - fragments.modules.flatMap { it.fragments }, + generateWrappedModuleBody( + multiModule = true, + mainModuleName = mainModuleName, + moduleKind = moduleKind, + jsIrProgram, sourceMapsInfo = null, + relativeRequirePath = false, generateScriptModule = false, - generateCallToMain = true, ), null ) } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformerTmp.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformerTmp.kt index 5d28614058a..7dce4f3fa6d 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformerTmp.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformerTmp.kt @@ -283,7 +283,7 @@ class IrModuleToJsTransformerTmp( } } -private fun generateWrappedModuleBody( +fun generateWrappedModuleBody( multiModule: Boolean, mainModuleName: String, moduleKind: ModuleKind, @@ -336,7 +336,7 @@ private fun generateWrappedModuleBody( } } -fun generateSingleWrappedModuleBody( +private fun generateSingleWrappedModuleBody( moduleName: String, moduleKind: ModuleKind, fragments: List, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/MultiModuleSupport.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/MultiModuleSupport.kt index c5e0653a37f..0092940a9bf 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/MultiModuleSupport.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/MultiModuleSupport.kt @@ -117,8 +117,11 @@ fun buildCrossModuleReferenceInfo(modules: Iterable): CrossMod } val IrModuleFragment.safeName: String + get() = name.asString().safeModuleName + +val String.safeModuleName: String get() { - var result = name.asString() + var result = this if (result.startsWith('<')) result = result.substring(1) if (result.endsWith('>')) result = result.substring(0, result.length - 1) 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 72cd383ffb8..73e13798c1a 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 @@ -52,6 +52,8 @@ interface PersistentCacheProvider { fun filePaths(): Iterable + fun moduleName(): String + companion object { val EMPTY = object : PersistentCacheProvider { override fun fileFingerPrint(path: String): Hash { @@ -87,6 +89,10 @@ interface PersistentCacheProvider { } override fun filePaths(): Iterable = emptyList() + + override fun moduleName(): String { + TODO("Not yet implemented") + } } } } @@ -192,6 +198,10 @@ class PersistentCacheProviderImpl(private val cachePath: String) : PersistentCac } else null } } + + override fun moduleName(): String { + TODO("Not yet implemented") + } } interface PersistentCacheConsumer { @@ -205,6 +215,7 @@ interface PersistentCacheConsumer { fun invalidateForFile(path: String) fun commitLibraryPath(libraryPath: String, flatHash: ULong, transHash: ULong) + fun commitModuleName(moduleName: String) companion object { val EMPTY = object : PersistentCacheConsumer { @@ -246,6 +257,9 @@ interface PersistentCacheConsumer { override fun commitSourceMap(path: String, mapData: ByteArray) { } + + override fun commitModuleName(moduleName: String) { + } } } } @@ -347,4 +361,8 @@ class PersistentCacheConsumerImpl(private val cachePath: String) : PersistentCac it.println(transHash.toString(16)) } } + + override fun commitModuleName(moduleName: String) { + TODO("Not yet implemented") + } } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JsEnvironmentConfigurationDirectives.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JsEnvironmentConfigurationDirectives.kt index ed1c076cd9c..d9093b60325 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JsEnvironmentConfigurationDirectives.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JsEnvironmentConfigurationDirectives.kt @@ -239,4 +239,11 @@ object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() { description = "", applicability = DirectiveApplicability.Global ) + + val NO_COMMON_FILES by directive( + """ + Don't added helper files to prevent linking issues. + """.trimIndent(), + applicability = DirectiveApplicability.Global, + ) } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt index a7a79b5373d..612e6f94365 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JsEnvironmentConfigurator.kt @@ -53,6 +53,7 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu const val OLD_MODULE_SUFFIX = "_old" private const val OUTPUT_DIR_NAME = "outputDir" + private const val RECOMPILED_OUTPUT_DIR_NAME = "outputDir-recompiled" private const val OUTPUT_KLIB_DIR_NAME = "outputKlibDir" private const val DCE_OUTPUT_DIR_NAME = "dceOutputDir" private const val MINIFICATION_OUTPUT_DIR_NAME = "minOutputDir" @@ -80,6 +81,10 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu return getJsArtifactsOutputDir(testServices).absolutePath + File.separator + getJsArtifactSimpleName(testServices, moduleName) + "_v5" } + fun getRecompiledJsModuleArtifactPath(testServices: TestServices, moduleName: String): String { + return getJsArtifactsRecompiledOutputDir(testServices).absolutePath + File.separator + getJsArtifactSimpleName(testServices, moduleName) + "_v5" + } + fun getJsKlibArtifactPath(testServices: TestServices, moduleName: String): String { return getJsKlibOutputDir(testServices).absolutePath + File.separator + getJsArtifactSimpleName(testServices, moduleName) } @@ -92,6 +97,10 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(OUTPUT_DIR_NAME) } + fun getJsArtifactsRecompiledOutputDir(testServices: TestServices): File { + return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(RECOMPILED_OUTPUT_DIR_NAME) + } + fun getJsKlibOutputDir(testServices: TestServices): File { return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(OUTPUT_KLIB_DIR_NAME) } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/JsAdditionalSourceProvider.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/JsAdditionalSourceProvider.kt index b539914f752..443b4a72cfa 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/JsAdditionalSourceProvider.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/JsAdditionalSourceProvider.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.js.test import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.js.JavaScript +import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives import org.jetbrains.kotlin.test.model.TestFile import org.jetbrains.kotlin.test.model.TestModule @@ -18,6 +19,7 @@ import java.io.FileFilter class JsAdditionalSourceProvider(testServices: TestServices) : AdditionalSourceProvider(testServices) { override fun produceAdditionalFiles(globalDirectives: RegisteredDirectives, module: TestModule): List { + if (JsEnvironmentConfigurationDirectives.NO_COMMON_FILES in module.directives) return emptyList() return getAdditionalKotlinFiles(module.files.first().originalFile.parent).map { it.toTestFile() } } 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 b200e4e6957..a92fad4d100 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 @@ -92,8 +92,7 @@ class JsIrBackendFacade( val outputFile = if (firstTimeCompilation) { File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + ".js") } else { - val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + ".js") - File(outputFile.parentFile, outputFile.nameWithoutExtension + "-recompiled.js") + File(JsEnvironmentConfigurator.getRecompiledJsModuleArtifactPath(testServices, module.name) + ".js") } val moduleName = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME) val moduleKind = configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN) @@ -296,8 +295,7 @@ class JsIrBackendFacade( dependencies.forEach { (moduleId, outputs) -> val moduleWrappedCode = ClassicJsBackendFacade.wrapWithModuleEmulationMarkers(outputs.jsCode, moduleKind, moduleId) - val dependencyPath = outputFile.absolutePath.replace("_v5.js", "-${moduleId}_v5.js") - File(dependencyPath).write(moduleWrappedCode) + outputFile.augmentWithModuleName(moduleId).write(moduleWrappedCode) } } @@ -326,4 +324,9 @@ class JsIrBackendFacade( override fun shouldRunAnalysis(module: TestModule): Boolean { return JsEnvironmentConfigurator.isMainModule(module, testServices) } +} + +fun File.augmentWithModuleName(moduleName: String): File { + check(absolutePath.endsWith("_v5.js")) + return File(absolutePath.removeSuffix("_v5.js") + "-${moduleName}_v5.js") } \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/handlers/JsIrRecompiledArtifactsIdentityHandler.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/handlers/JsIrRecompiledArtifactsIdentityHandler.kt index 59226dbaca1..bf8283acfd4 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/handlers/JsIrRecompiledArtifactsIdentityHandler.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/handlers/JsIrRecompiledArtifactsIdentityHandler.kt @@ -6,11 +6,15 @@ package org.jetbrains.kotlin.js.test.handlers import com.intellij.openapi.util.io.FileUtil +import org.jetbrains.kotlin.fir.backend.FirMetadataSource +import org.jetbrains.kotlin.js.test.converters.ClassicJsBackendFacade +import org.jetbrains.kotlin.js.test.converters.augmentWithModuleName import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler import org.jetbrains.kotlin.test.model.BinaryArtifacts.Js import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.assertions +import java.io.File class JsIrRecompiledArtifactsIdentityHandler(testServices: TestServices) : JsBinaryArtifactHandler(testServices) { override fun processModule(module: TestModule, info: Js) { @@ -46,10 +50,28 @@ class JsIrRecompiledArtifactsIdentityHandler(testServices: TestServices) : JsBin } } - val originalOutput = FileUtil.loadFile(originalArtifact.outputFile) - val recompiledOutput = FileUtil.loadFile(incrementalArtifact.outputFile) - testServices.assertions.assertEquals(originalOutput, recompiledOutput) { "Output file changed after recompilation" } + val originalFilesToCheck = originalArtifact.allFiles() + val recompiledFilesToCheck = incrementalArtifact.allFiles() + + testServices.assertions.assertEquals(originalFilesToCheck.size, recompiledFilesToCheck.size) + + for ((originalFile, recompiledFile) in originalFilesToCheck.zip(recompiledFilesToCheck)) { + testServices.assertions.assertEquals(originalFile.name, recompiledFile.name) + + val originalOutput = FileUtil.loadFile(originalFile) + val recompiledOutput = FileUtil.loadFile(recompiledFile) + + testServices.assertions.assertEquals(originalOutput, recompiledOutput) { + "Output file changed after recompilation" + } + } } override fun processAfterAllModules(someAssertionWasFailed: Boolean) {} } + +private fun Js.JsIrArtifact.allFiles(): Collection { + return listOf(outputFile) + compilerResult.outputs!!.dependencies.map { (moduleId, _) -> + outputFile.augmentWithModuleName(moduleId) + }.sortedBy { it.name } +} 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 2bfaf255590..49439280e51 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 @@ -25,9 +25,11 @@ import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurato import org.jetbrains.kotlin.test.services.jsLibraryProvider import java.io.File -class TestModuleCache(val moduleName: String, val files: MutableMap) { +class TestModuleCache(val files: MutableMap) { - constructor(moduleName: String) : this(moduleName, mutableMapOf()) + constructor() : this(mutableMapOf()) + + private lateinit var storedModuleName: String fun cacheProvider(): PersistentCacheProvider { return object : PersistentCacheProvider { @@ -66,6 +68,10 @@ class TestModuleCache(val moduleName: String, val files: MutableMap { return files.keys } + + override fun moduleName(): String { + return storedModuleName + } } } @@ -117,10 +123,14 @@ class TestModuleCache(val moduleName: String, val files: MutableMap