From cacfe530650b87114b7921fc3b83b65a6973371c Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Mon, 1 Feb 2021 15:52:05 +0300 Subject: [PATCH] IR: move performByIrFile to a separate .kt --- .../backend/common/phaser/PhaseBuilders.kt | 194 ----------------- .../backend/common/phaser/performByIrFile.kt | 204 ++++++++++++++++++ 2 files changed, 204 insertions(+), 194 deletions(-) create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/performByIrFile.kt 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 f9f676401df..feee4277c2e 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 @@ -5,30 +5,12 @@ package org.jetbrains.kotlin.backend.common.phaser -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.IrStatement import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.symbols.IrFileSymbol -import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol -import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper -import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom -import org.jetbrains.kotlin.ir.util.deepCopySavingMetadata -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicReference // Phase composition. private class CompositePhase( @@ -116,105 +98,6 @@ fun namedOpUnitPhase( } ) -fun performByIrFile( - name: String = "PerformByIrFile", - description: String = "Perform phases by IrFile", - lower: List> -): NamedCompilerPhase = - NamedCompilerPhase( - name, description, emptySet(), PerformByIrFilePhase(lower), emptySet(), emptySet(), emptySet(), - setOf(defaultDumper), nlevels = 1, - ) - -private class PerformByIrFilePhase( - private val lower: List> -) : SameTypeCompilerPhase { - override fun invoke( - phaseConfig: PhaseConfig, - phaserState: PhaserState, - context: Context, - input: IrModuleFragment - ): IrModuleFragment { - val nThreads = context.configuration.get(CommonConfigurationKeys.PARALLEL_BACKEND_THREADS) ?: 1 - return if (nThreads > 1) - invokeParallel(phaseConfig, phaserState, context, input, nThreads) - 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, filePhaserState, context, irFile) - } - } catch (e: Throwable) { - CodegenUtil.reportBackendException(e, "IR lowering", irFile.fileEntry.name) - } - } - - // TODO: no guarantee that module identity is preserved by `lower` - return input - } - - private fun invokeParallel( - phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment, nThreads: Int - ): IrModuleFragment { - if (input.files.isEmpty()) return input - - // We can only report one exception through ISE - val thrownFromThread = AtomicReference?>(null) - - val remappedFiles = mutableMapOf() - val remappedFunctions = mutableMapOf() - val remappedClasses = mutableMapOf() - - // Each thread needs its own copy of phaserState.alreadyDone - val filesAndStates = input.files.map { - it.copySavingMappings(remappedFiles, remappedFunctions, remappedClasses) to phaserState.copyOf() - } - - val executor = Executors.newFixedThreadPool(nThreads) - for ((irFile, state) in filesAndStates) { - executor.execute { - try { - val filePhaserState = state.changeType() - for (phase in lower) { - phase.invoke(phaseConfig, filePhaserState, context, irFile) - } - } catch (e: Throwable) { - thrownFromThread.set(Pair(e, irFile)) - } - } - } - executor.shutdown() - executor.awaitTermination(1, TimeUnit.DAYS) // Wait long enough - - thrownFromThread.get()?.let { (e, irFile) -> - CodegenUtil.reportBackendException(e, "IrLowering", irFile.fileEntry.name) - } - - // Presumably each thread has run through the same list of phases. - phaserState.alreadyDone.addAll(filesAndStates[0].second.alreadyDone) - - input.files.clear() - input.files.addAll(filesAndStates.map { (irFile, _) -> irFile }.toMutableList()) - - adjustDefaultArgumentStubs(context, remappedFunctions) - context.handleDeepCopy(remappedFiles, remappedClasses, remappedFunctions) - input.transformChildrenVoid(CrossFileCallAdjuster(remappedFunctions)) - - // TODO: no guarantee that module identity is preserved by `lower` - return input - } - - override fun getNamedSubphases(startDepth: Int): List>> = - lower.flatMap { it.getNamedSubphases(startDepth) } -} - fun makeIrFilePhase( lowering: (Context) -> FileLoweringPass, name: String, @@ -282,80 +165,3 @@ fun transform(op: (OldData) - object : CompilerPhase { override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: OldData) = op(input) } - -// We need to remap inline function calls after lowering files - -fun IrFile.copySavingMappings( - remappedFiles: MutableMap, - remappedFunctions: MutableMap, - remappedClasses: MutableMap, -): IrFile { - val symbolRemapper = DeepCopySymbolRemapperSavingFunctions() - - val newIrFile = deepCopySavingMetadata(symbolRemapper = symbolRemapper) - - for (function in symbolRemapper.declaredFunctions) { - remappedFunctions[function] = symbolRemapper.getReferencedSimpleFunction(function) - } - for (klass in symbolRemapper.declaredClasses) { - remappedClasses[klass] = symbolRemapper.getReferencedClass(klass) - } - - remappedFiles[symbol] = newIrFile.symbol - - return newIrFile -} - -private class DeepCopySymbolRemapperSavingFunctions : DeepCopySymbolRemapper() { - val declaredFunctions = mutableSetOf() - val declaredClasses = mutableSetOf() - - override fun getDeclaredFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol { - declaredFunctions.add(symbol) - return super.getDeclaredFunction(symbol) - } - - override fun getDeclaredClass(symbol: IrClassSymbol): IrClassSymbol { - declaredClasses.add(symbol) - return super.getDeclaredClass(symbol) - } -} - -fun adjustDefaultArgumentStubs( - context: CommonBackendContext, - remappedFunctions: MutableMap, -) { - for (defaultStub in context.mapping.defaultArgumentsOriginalFunction.keys) { - if (defaultStub !is IrSimpleFunction) continue - val original = context.mapping.defaultArgumentsOriginalFunction[defaultStub] as? IrSimpleFunction ?: continue - val originalNew = remappedFunctions[original.symbol]?.owner ?: continue - val defaultStubNew = context.mapping.defaultArgumentsDispatchFunction[originalNew] ?: continue - remappedFunctions[defaultStub.symbol] = defaultStubNew.symbol as IrSimpleFunctionSymbol - } -} - -private class CrossFileCallAdjuster( - val remappedFunctions: Map -) : IrElementTransformerVoid() { - - override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement { - declaration.overriddenSymbols = declaration.overriddenSymbols.map { remappedFunctions[it] ?: it } - return super.visitSimpleFunction(declaration) - } - - override fun visitCall(expression: IrCall): IrExpression { - expression.transformChildrenVoid(this) - return remappedFunctions[expression.symbol]?.let { newSymbol -> - with(expression) { - IrCallImpl( - startOffset, endOffset, type, - newSymbol, - typeArgumentsCount, valueArgumentsCount, origin, - superQualifierSymbol // TODO - ).apply { - copyTypeAndValueArgumentsFrom(expression) - } - } - } ?: expression - } -} \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/performByIrFile.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/performByIrFile.kt new file mode 100644 index 00000000000..1d803aea687 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/phaser/performByIrFile.kt @@ -0,0 +1,204 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.phaser + +import org.jetbrains.kotlin.backend.common.CodegenUtil +import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrFileSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper +import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom +import org.jetbrains.kotlin.ir.util.deepCopySavingMetadata +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicReference + +fun performByIrFile( + name: String = "PerformByIrFile", + description: String = "Perform phases by IrFile", + lower: List> +): NamedCompilerPhase = + NamedCompilerPhase( + name, description, emptySet(), PerformByIrFilePhase(lower), emptySet(), emptySet(), emptySet(), + setOf(defaultDumper), nlevels = 1, + ) + +private class PerformByIrFilePhase( + private val lower: List> +) : SameTypeCompilerPhase { + override fun invoke( + phaseConfig: PhaseConfig, + phaserState: PhaserState, + context: Context, + input: IrModuleFragment + ): IrModuleFragment { + val nThreads = context.configuration.get(CommonConfigurationKeys.PARALLEL_BACKEND_THREADS) ?: 1 + return if (nThreads > 1) + invokeParallel(phaseConfig, phaserState, context, input, nThreads) + 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, filePhaserState, context, irFile) + } + } catch (e: Throwable) { + CodegenUtil.reportBackendException(e, "IR lowering", irFile.fileEntry.name) + } + } + + // TODO: no guarantee that module identity is preserved by `lower` + return input + } + + private fun invokeParallel( + phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment, nThreads: Int + ): IrModuleFragment { + if (input.files.isEmpty()) return input + + // We can only report one exception through ISE + val thrownFromThread = AtomicReference?>(null) + + val remappedFiles = mutableMapOf() + val remappedFunctions = mutableMapOf() + val remappedClasses = mutableMapOf() + + // Each thread needs its own copy of phaserState.alreadyDone + val filesAndStates = input.files.map { + it.copySavingMappings(remappedFiles, remappedFunctions, remappedClasses) to phaserState.copyOf() + } + + val executor = Executors.newFixedThreadPool(nThreads) + for ((irFile, state) in filesAndStates) { + executor.execute { + try { + val filePhaserState = state.changeType() + for (phase in lower) { + phase.invoke(phaseConfig, filePhaserState, context, irFile) + } + } catch (e: Throwable) { + thrownFromThread.set(Pair(e, irFile)) + } + } + } + executor.shutdown() + executor.awaitTermination(1, TimeUnit.DAYS) // Wait long enough + + thrownFromThread.get()?.let { (e, irFile) -> + CodegenUtil.reportBackendException(e, "Experimental parallel IR backend", irFile.fileEntry.name) + } + + // Presumably each thread has run through the same list of phases. + phaserState.alreadyDone.addAll(filesAndStates[0].second.alreadyDone) + + input.files.clear() + input.files.addAll(filesAndStates.map { (irFile, _) -> irFile }.toMutableList()) + + adjustDefaultArgumentStubs(context, remappedFunctions) + context.handleDeepCopy(remappedFiles, remappedClasses, remappedFunctions) + input.transformChildrenVoid(CrossFileCallAdjuster(remappedFunctions)) + + // TODO: no guarantee that module identity is preserved by `lower` + return input + } + + override fun getNamedSubphases(startDepth: Int): List>> = + lower.flatMap { it.getNamedSubphases(startDepth) } +} + +// We need to remap inline function calls after lowering files + +fun IrFile.copySavingMappings( + remappedFiles: MutableMap, + remappedFunctions: MutableMap, + remappedClasses: MutableMap, +): IrFile { + val symbolRemapper = DeepCopySymbolRemapperSavingFunctions() + + val newIrFile = deepCopySavingMetadata(symbolRemapper = symbolRemapper) + + for (function in symbolRemapper.declaredFunctions) { + remappedFunctions[function] = symbolRemapper.getReferencedSimpleFunction(function) + } + for (klass in symbolRemapper.declaredClasses) { + remappedClasses[klass] = symbolRemapper.getReferencedClass(klass) + } + + remappedFiles[symbol] = newIrFile.symbol + + return newIrFile +} + +private class DeepCopySymbolRemapperSavingFunctions : DeepCopySymbolRemapper() { + val declaredFunctions = mutableSetOf() + val declaredClasses = mutableSetOf() + + override fun getDeclaredFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol { + declaredFunctions.add(symbol) + return super.getDeclaredFunction(symbol) + } + + override fun getDeclaredClass(symbol: IrClassSymbol): IrClassSymbol { + declaredClasses.add(symbol) + return super.getDeclaredClass(symbol) + } +} + +private fun adjustDefaultArgumentStubs( + context: CommonBackendContext, + remappedFunctions: MutableMap, +) { + for (defaultStub in context.mapping.defaultArgumentsOriginalFunction.keys) { + if (defaultStub !is IrSimpleFunction) continue + val original = context.mapping.defaultArgumentsOriginalFunction[defaultStub] as? IrSimpleFunction ?: continue + val originalNew = remappedFunctions[original.symbol]?.owner ?: continue + val defaultStubNew = context.mapping.defaultArgumentsDispatchFunction[originalNew] ?: continue + remappedFunctions[defaultStub.symbol] = defaultStubNew.symbol as IrSimpleFunctionSymbol + } +} + +private class CrossFileCallAdjuster( + val remappedFunctions: Map +) : IrElementTransformerVoid() { + + override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement { + declaration.overriddenSymbols = declaration.overriddenSymbols.map { remappedFunctions[it] ?: it } + return super.visitSimpleFunction(declaration) + } + + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + return remappedFunctions[expression.symbol]?.let { newSymbol -> + with(expression) { + IrCallImpl( + startOffset, endOffset, type, + newSymbol, + typeArgumentsCount, valueArgumentsCount, origin, + superQualifierSymbol // TODO + ).apply { + copyTypeAndValueArgumentsFrom(expression) + } + } + } ?: expression + } +} \ No newline at end of file