diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index 2690da7b26f..bb910106471 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -114,6 +114,12 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { ) var doNotClearBindingContext: Boolean by FreezableVar(false) + @Argument( + value = "-Xir-run-lowerings-in-parallel", + description = "When using the IR backend, run lowerings for each file in parallel" + ) + var runLoweringsInParallel: Boolean by FreezableVar(false) + @Argument(value = "-Xmodule-path", valueDescription = "", description = "Paths where to find Java 9+ modules") var javaModulePath: String? by NullableStringFreezableVar(null) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt index 84ab300d7db..196e5915734 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt @@ -291,6 +291,8 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr } arguments.declarationsOutputPath?.let { put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) } + + put(CommonConfigurationKeys.RUN_LOWERINGS_IN_PARALLEL, arguments.runLoweringsInParallel) } fun CompilerConfiguration.configureKlibPaths(arguments: K2JVMCompilerArguments) { diff --git a/compiler/config/src/org/jetbrains/kotlin/config/CommonConfigurationKeys.kt b/compiler/config/src/org/jetbrains/kotlin/config/CommonConfigurationKeys.kt index a26f51a3eae..f3eddf8e8ae 100644 --- a/compiler/config/src/org/jetbrains/kotlin/config/CommonConfigurationKeys.kt +++ b/compiler/config/src/org/jetbrains/kotlin/config/CommonConfigurationKeys.kt @@ -50,6 +50,10 @@ object CommonConfigurationKeys { @JvmField val USE_FIR_EXTENDED_CHECKERS = CompilerConfigurationKey.create("fir extended checkers") + + @JvmField + val RUN_LOWERINGS_IN_PARALLEL = + CompilerConfigurationKey.create("When using the IR backend, run lowerings for each file in parallel") } var CompilerConfiguration.languageVersionSettings: LanguageVersionSettings diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/PhaseBuilders.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/PhaseBuilders.kt index 6924d2f019c..1d0dd9bdb48 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/PhaseBuilders.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/PhaseBuilders.kt @@ -9,9 +9,11 @@ import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.lower +import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import kotlin.concurrent.thread // Phase composition. private class CompositePhase( @@ -113,12 +115,23 @@ private class PerformByIrFilePhase( private val lower: List> ) : SameTypeCompilerPhase { override fun invoke( + phaseConfig: PhaseConfig, + phaserState: PhaserState, + context: Context, + input: IrModuleFragment + ): IrModuleFragment = if (context.configuration.getBoolean(CommonConfigurationKeys.RUN_LOWERINGS_IN_PARALLEL)) + invokeParallel(phaseConfig, phaserState, context, input) + else + invokeSequential(phaseConfig, phaserState, context, input) + + private fun invokeSequential( phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment ): IrModuleFragment { for (irFile in input.files) { try { + val filePhaserState = phaserState.changeType() for (phase in lower) { - phase.invoke(phaseConfig, phaserState.changeType(), context, irFile) + phase.invoke(phaseConfig, filePhaserState, context, irFile) } } catch (e: Throwable) { CodegenUtil.reportBackendException(e, "IR lowering", irFile.fileEntry.name) @@ -129,6 +142,28 @@ private class PerformByIrFilePhase( return input } + private fun invokeParallel( + phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment + ): IrModuleFragment { + val threads = input.files.map { irFile -> + thread { + try { + val filePhaserState = state.changeType() + for (phase in lower) { + phase.invoke(phaseConfig, filePhaserState, context, irFile) + } + } catch (e: Throwable) { + CodegenUtil.reportBackendException(e, "IR lowering", irFile.fileEntry.name) + } + } + } + + threads.forEach { it.join() } + + // TODO: no guarantee that module identity is preserved by `lower` + return input + } + override fun getNamedSubphases(startDepth: Int): List>> = lower.flatMap { it.getNamedSubphases(startDepth) } } diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index 374d9ca8499..836d1d04734 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -99,6 +99,7 @@ where advanced options include: -Xsam-conversions={class|indy} Select code generation scheme for SAM conversions. -Xsam-conversions=indy Generate SAM conversions using `invokedynamic` with `LambdaMetafactory.metafactory`. Requires `-jvm-target 1.8` or greater. -Xsam-conversions=class Generate SAM conversions as explicit classes + -Xir-run-lowerings-in-parallel When using the IR backend, run lowerings for each file in parallel -Xsanitize-parentheses Transform '(' and ')' in method names to some other character sequence. This mode can BREAK BINARY COMPATIBILITY and is only supposed to be used to workaround problems with parentheses in identifiers on certain platforms