From 75142230b636a10fe89e37c1a657cc726a1b7d4d Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Wed, 26 Jul 2023 16:25:58 +0200 Subject: [PATCH] [Wasm] Support Wasm K2 frontend in CLI (KT-57230) --- .../jetbrains/kotlin/cli/js/K2JsIrCompiler.kt | 5 +- .../kotlin/cli/js/klib/compilerPipeline.kt | 47 +++++++++++++---- .../cli/common/FirSessionConstructionUtils.kt | 50 +++++++++++++++++++ .../FirAbstractInvalidationTest.kt | 4 +- 4 files changed, 93 insertions(+), 13 deletions(-) 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 adb30ba568f..7ae90a4737a 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 @@ -509,6 +509,7 @@ class K2JsIrCompiler : CLICompiler() { diagnosticsReporter = diagnosticsReporter, incrementalDataProvider = configuration[JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER], lookupTracker = lookupTracker, + useWasmPlatform = arguments.wasm, ) } else { compileModuleToAnalyzedFirWithPsi( @@ -519,6 +520,7 @@ class K2JsIrCompiler : CLICompiler() { diagnosticsReporter = diagnosticsReporter, incrementalDataProvider = configuration[JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER], lookupTracker = lookupTracker, + useWasmPlatform = arguments.wasm, ) } @@ -550,7 +552,8 @@ class K2JsIrCompiler : CLICompiler() { outputKlibPath = outputKlibPath, messageCollector = messageCollector, diagnosticsReporter = diagnosticsReporter, - jsOutputName = arguments.irPerModuleOutputName + jsOutputName = arguments.irPerModuleOutputName, + useWasmPlatform = arguments.wasm ) } diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt index 095180014df..e03c2becd4c 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt @@ -40,13 +40,16 @@ import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices import org.jetbrains.kotlin.library.KotlinAbiVersion +import org.jetbrains.kotlin.library.impl.BuiltInsPlatform import org.jetbrains.kotlin.library.unresolvedDependencies import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.js.JsPlatforms +import org.jetbrains.kotlin.platform.wasm.WasmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.utils.metadataVersion +import org.jetbrains.kotlin.wasm.resolve.WasmPlatformAnalyzerServices import java.io.File import java.nio.file.Paths @@ -60,6 +63,7 @@ inline fun compileModuleToAnalyzedFir( noinline isCommonSource: (F) -> Boolean, noinline fileBelongsToModule: (F, String) -> Boolean, buildResolveAndCheckFir: (FirSession, List) -> ModuleCompilerAnalyzedOutput, + useWasmPlatform: Boolean, ): List { // FIR val extensionRegistrars = FirExtensionRegistrar.getInstances(moduleStructure.project) @@ -67,7 +71,10 @@ inline fun compileModuleToAnalyzedFir( val mainModuleName = moduleStructure.compilerConfiguration.get(CommonConfigurationKeys.MODULE_NAME)!! val escapedMainModuleName = Name.special("<$mainModuleName>") - val binaryModuleData = BinaryModuleData.initialize(escapedMainModuleName, JsPlatforms.defaultJsPlatform, JsPlatformAnalyzerServices) + val platform = if (useWasmPlatform) WasmPlatforms.Default else JsPlatforms.defaultJsPlatform + val platformAnalyzerServices = if (useWasmPlatform) WasmPlatformAnalyzerServices else JsPlatformAnalyzerServices + + val binaryModuleData = BinaryModuleData.initialize(escapedMainModuleName, platform, platformAnalyzerServices) val dependencyList = DependencyListForCliModule.build(binaryModuleData) { dependencies(libraries.map { Paths.get(it).toAbsolutePath() }) friendDependencies(friendLibraries.map { Paths.get(it).toAbsolutePath() }) @@ -75,14 +82,26 @@ inline fun compileModuleToAnalyzedFir( } val resolvedLibraries = moduleStructure.allDependencies - val sessionsWithSources = prepareJsSessions( - files, moduleStructure.compilerConfiguration, escapedMainModuleName, - resolvedLibraries, dependencyList, extensionRegistrars, - isCommonSource = isCommonSource, - fileBelongsToModule = fileBelongsToModule, - lookupTracker, - icData = incrementalDataProvider?.let(::KlibIcData), - ) + + val sessionsWithSources = if (useWasmPlatform) { + prepareWasmSessions( + files, moduleStructure.compilerConfiguration, escapedMainModuleName, + resolvedLibraries, dependencyList, extensionRegistrars, + isCommonSource = isCommonSource, + fileBelongsToModule = fileBelongsToModule, + lookupTracker, + icData = incrementalDataProvider?.let(::KlibIcData), + ) + } else { + prepareJsSessions( + files, moduleStructure.compilerConfiguration, escapedMainModuleName, + resolvedLibraries, dependencyList, extensionRegistrars, + isCommonSource = isCommonSource, + fileBelongsToModule = fileBelongsToModule, + lookupTracker, + icData = incrementalDataProvider?.let(::KlibIcData), + ) + } val outputs = sessionsWithSources.map { buildResolveAndCheckFir(it.session, it.files) @@ -128,6 +147,7 @@ fun compileModuleToAnalyzedFirWithPsi( diagnosticsReporter: BaseDiagnosticsCollector, incrementalDataProvider: IncrementalDataProvider?, lookupTracker: LookupTracker?, + useWasmPlatform: Boolean, ): AnalyzedFirWithPsiOutput { val output = compileModuleToAnalyzedFir( moduleStructure, @@ -141,6 +161,7 @@ fun compileModuleToAnalyzedFirWithPsi( buildResolveAndCheckFir = { session, files -> buildResolveAndCheckFirFromKtFiles(session, files, diagnosticsReporter) }, + useWasmPlatform = useWasmPlatform, ) return AnalyzedFirWithPsiOutput(output, ktFiles) } @@ -154,6 +175,7 @@ fun compileModulesToAnalyzedFirWithLightTree( diagnosticsReporter: BaseDiagnosticsCollector, incrementalDataProvider: IncrementalDataProvider?, lookupTracker: LookupTracker?, + useWasmPlatform: Boolean, ): AnalyzedFirOutput { val output = compileModuleToAnalyzedFir( moduleStructure, @@ -167,6 +189,7 @@ fun compileModulesToAnalyzedFirWithLightTree( buildResolveAndCheckFir = { session, files -> buildResolveAndCheckFirViaLightTree(session, files, diagnosticsReporter, null) }, + useWasmPlatform = useWasmPlatform, ) return AnalyzedFirOutput(output) } @@ -275,7 +298,8 @@ fun serializeFirKlib( outputKlibPath: String, messageCollector: MessageCollector, diagnosticsReporter: BaseDiagnosticsCollector, - jsOutputName: String? + jsOutputName: String?, + useWasmPlatform: Boolean, ) { val fir2KlibSerializer = Fir2KlibSerializer(moduleStructure, firOutputs, fir2IrActualizedResult) val icData = moduleStructure.compilerConfiguration.incrementalDataProvider?.getSerializedData(fir2KlibSerializer.sourceFiles) @@ -295,7 +319,8 @@ fun serializeFirKlib( containsErrorCode = messageCollector.hasErrors() || diagnosticsReporter.hasErrors, abiVersion = KotlinAbiVersion.CURRENT, // TODO get from test file data jsOutputName = jsOutputName, - serializeSingleFile = fir2KlibSerializer::serializeSingleFirFile + serializeSingleFile = fir2KlibSerializer::serializeSingleFirFile, + builtInsPlatform = if (useWasmPlatform) BuiltInsPlatform.WASM else BuiltInsPlatform.JS, ) } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt index 8f7d0d6f720..682815ac8d8 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt @@ -24,15 +24,18 @@ import org.jetbrains.kotlin.load.kotlin.PackageAndMetadataPartProvider import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.CommonPlatforms import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.platform.WasmPlatform import org.jetbrains.kotlin.platform.js.JsPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.konan.NativePlatforms +import org.jetbrains.kotlin.platform.wasm.WasmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices import org.jetbrains.kotlin.resolve.multiplatform.hmppModuleName import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource +import org.jetbrains.kotlin.wasm.resolve.WasmPlatformAnalyzerServices val isCommonSourceForPsi: (KtFile) -> Boolean = { it.isCommonSource == true } val fileBelongsToModuleForPsi: (KtFile, String) -> Boolean = { file, moduleName -> file.hmppModuleName == moduleName } @@ -189,6 +192,53 @@ fun prepareNativeSessions( } } +/** + * Creates library session and sources session for Wasm platform + * Number of created session depends on mode of MPP: + * - disabled + * - legacy (one platform and one common module) + * - HMPP (multiple number of modules) + */ +fun prepareWasmSessions( + files: List, + configuration: CompilerConfiguration, + rootModuleName: Name, + resolvedLibraries: List, + libraryList: DependencyListForCliModule, + extensionRegistrars: List, + isCommonSource: (F) -> Boolean, + fileBelongsToModule: (F, String) -> Boolean, + lookupTracker: LookupTracker?, + icData: KlibIcData?, +): List> { + return prepareSessions( + files, configuration, rootModuleName, WasmPlatforms.Default, WasmPlatformAnalyzerServices, + metadataCompilationMode = false, libraryList, isCommonSource, fileBelongsToModule, + createLibrarySession = { sessionProvider -> + FirWasmSessionFactory.createLibrarySession( + rootModuleName, + resolvedLibraries, + sessionProvider, + libraryList.moduleDataProvider, + extensionRegistrars, + configuration.languageVersionSettings, + registerExtraComponents = {}, + ) + } + ) { _, moduleData, sessionProvider, sessionConfigurator -> + FirWasmSessionFactory.createModuleBasedSession( + moduleData, + sessionProvider, + extensionRegistrars, + configuration.languageVersionSettings, + lookupTracker, + icData = icData, + registerExtraComponents = {}, + init = sessionConfigurator, + ) + } +} + /** * Creates library session and sources session for Common platform (for metadata compilation) * Number of created sessions is always one, in this mode modules are compiled against compiled diff --git a/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt index 9652dae6566..11af9d5e322 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/FirAbstractInvalidationTest.kt @@ -76,6 +76,7 @@ abstract class FirAbstractInvalidationTest( diagnosticsReporter = diagnosticsReporter, incrementalDataProvider = null, lookupTracker = null, + useWasmPlatform = false, ) val fir2IrActualizedResult = transformFirToIr(moduleStructure, analyzedOutput.output, diagnosticsReporter) @@ -92,7 +93,8 @@ abstract class FirAbstractInvalidationTest( outputKlibPath = outputKlibFile.absolutePath, messageCollector = messageCollector, diagnosticsReporter = diagnosticsReporter, - jsOutputName = moduleName + jsOutputName = moduleName, + useWasmPlatform = false, ) if (messageCollector.hasErrors()) {